diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/third_party/WebKit/Source/core/rendering | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/rendering')
468 files changed, 25079 insertions, 30452 deletions
diff --git a/chromium/third_party/WebKit/Source/core/rendering/AbstractInlineTextBox.cpp b/chromium/third_party/WebKit/Source/core/rendering/AbstractInlineTextBox.cpp index a14b4a0e876..82c182e1d9c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/AbstractInlineTextBox.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/AbstractInlineTextBox.cpp @@ -41,7 +41,7 @@ AbstractInlineTextBox::InlineToAbstractInlineTextBoxHashMap* AbstractInlineTextB PassRefPtr<AbstractInlineTextBox> AbstractInlineTextBox::getOrCreate(RenderText* renderText, InlineTextBox* inlineTextBox) { if (!inlineTextBox) - return 0; + return nullptr; if (!gAbstractInlineTextBoxMap) gAbstractInlineTextBoxMap = new InlineToAbstractInlineTextBoxHashMap(); @@ -76,7 +76,7 @@ void AbstractInlineTextBox::detach() PassRefPtr<AbstractInlineTextBox> AbstractInlineTextBox::nextInlineTextBox() const { if (!m_inlineTextBox) - return 0; + return nullptr; return getOrCreate(m_renderText, m_inlineTextBox->nextTextBox()); } @@ -149,7 +149,7 @@ String AbstractInlineTextBox::text() const unsigned start = m_inlineTextBox->start(); unsigned len = m_inlineTextBox->len(); if (Node* node = m_renderText->node()) { - RefPtr<Range> range = Range::create(node->document()); + RefPtrWillBeRawPtr<Range> range = Range::create(node->document()); range->setStart(node, start, IGNORE_EXCEPTION); range->setEnd(node, start + len, IGNORE_EXCEPTION); return plainText(range.get(), TextIteratorIgnoresStyleVisibility); diff --git a/chromium/third_party/WebKit/Source/core/rendering/AutoTableLayout.cpp b/chromium/third_party/WebKit/Source/core/rendering/AutoTableLayout.cpp index 2c290c68fb1..eec5a0cd9f6 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/AutoTableLayout.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/AutoTableLayout.cpp @@ -22,6 +22,7 @@ #include "config.h" #include "core/rendering/AutoTableLayout.h" +#include "core/rendering/FastTextAutosizer.h" #include "core/rendering/RenderTable.h" #include "core/rendering/RenderTableCell.h" #include "core/rendering/RenderTableCol.h" @@ -65,7 +66,7 @@ void AutoTableLayout::recalcColumn(unsigned effCol) if (current.inColSpan || !cell) continue; - bool cellHasContent = cell->children()->firstChild() || cell->style()->hasBorder() || cell->style()->hasPadding(); + bool cellHasContent = cell->children()->firstChild() || cell->style()->hasBorder() || cell->style()->hasPadding() || cell->style()->hasBackground(); if (cellHasContent) columnLayout.emptyCellsOnly = false; @@ -207,6 +208,8 @@ static bool shouldScaleColumns(RenderTable* table) void AutoTableLayout::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) { + FastTextAutosizer::TableLayoutScope fastTextAutosizerTableLayoutScope(m_table); + fullRecalc(); int spanMaxLogicalWidth = calcEffectiveLogicalWidth(); @@ -247,8 +250,22 @@ void AutoTableLayout::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, Layout void AutoTableLayout::applyPreferredLogicalWidthQuirks(LayoutUnit& minWidth, LayoutUnit& maxWidth) const { Length tableLogicalWidth = m_table->style()->logicalWidth(); - if (tableLogicalWidth.isFixed() && tableLogicalWidth.isPositive()) + if (tableLogicalWidth.isFixed() && tableLogicalWidth.isPositive()) { + // |minWidth| is the result of measuring the intrinsic content's size. Keep it to + // make sure we are *never* smaller than the actual content. + LayoutUnit minContentWidth = minWidth; + // FIXME: This line looks REALLY suspicious as it could allow the minimum + // preferred logical width to be smaller than the table content. This has + // to be cross-checked against other browsers. minWidth = maxWidth = max<int>(minWidth, tableLogicalWidth.value()); + + const Length& styleMaxLogicalWidth = m_table->style()->logicalMaxWidth(); + if (styleMaxLogicalWidth.isFixed() && !styleMaxLogicalWidth.isNegative()) { + minWidth = min<int>(minWidth, styleMaxLogicalWidth.value()); + minWidth = max(minWidth, minContentWidth); + maxWidth = minWidth; + } + } } /* diff --git a/chromium/third_party/WebKit/Source/core/rendering/AutoTableLayout.h b/chromium/third_party/WebKit/Source/core/rendering/AutoTableLayout.h index dfdd985d842..9336d0f15a5 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/AutoTableLayout.h +++ b/chromium/third_party/WebKit/Source/core/rendering/AutoTableLayout.h @@ -34,7 +34,7 @@ class RenderTableCell; class AutoTableLayout FINAL : public TableLayout { public: AutoTableLayout(RenderTable*); - ~AutoTableLayout(); + virtual ~AutoTableLayout(); virtual void computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) OVERRIDE; virtual void applyPreferredLogicalWidthQuirks(LayoutUnit& minWidth, LayoutUnit& maxWidth) const OVERRIDE; diff --git a/chromium/third_party/WebKit/Source/core/rendering/BidiRun.h b/chromium/third_party/WebKit/Source/core/rendering/BidiRun.h index 85f8f4a1a1c..cd743385c06 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/BidiRun.h +++ b/chromium/third_party/WebKit/Source/core/rendering/BidiRun.h @@ -41,13 +41,8 @@ struct BidiRun : BidiCharacterRun { { // Stored in base class to save space. m_hasHyphen = false; - m_startsSegment = false; } - // BidiRuns are allocated out of the rendering partition. - void* operator new(size_t); - void operator delete(void*); - BidiRun* next() { return static_cast<BidiRun*>(m_next); } RenderObject* object() { return m_object; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/ClipPathOperation.h b/chromium/third_party/WebKit/Source/core/rendering/ClipPathOperation.h index 7d50a10e4fd..bf64113d848 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/ClipPathOperation.h +++ b/chromium/third_party/WebKit/Source/core/rendering/ClipPathOperation.h @@ -63,15 +63,15 @@ protected: OperationType m_type; }; -class ReferenceClipPathOperation : public ClipPathOperation { +class ReferenceClipPathOperation FINAL : public ClipPathOperation { public: - static PassRefPtr<ReferenceClipPathOperation> create(const String& url, const String& fragment) + static PassRefPtr<ReferenceClipPathOperation> create(const String& url, const AtomicString& fragment) { return adoptRef(new ReferenceClipPathOperation(url, fragment)); } const String& url() const { return m_url; } - const String& fragment() const { return m_fragment; } + const AtomicString& fragment() const { return m_fragment; } private: virtual bool operator==(const ClipPathOperation& o) const OVERRIDE @@ -79,7 +79,7 @@ private: return isSameType(o) && m_url == static_cast<const ReferenceClipPathOperation&>(o).m_url; } - ReferenceClipPathOperation(const String& url, const String& fragment) + ReferenceClipPathOperation(const String& url, const AtomicString& fragment) : ClipPathOperation(REFERENCE) , m_url(url) , m_fragment(fragment) @@ -87,12 +87,12 @@ private: } String m_url; - String m_fragment; + AtomicString m_fragment; }; DEFINE_TYPE_CASTS(ReferenceClipPathOperation, ClipPathOperation, op, op->type() == ClipPathOperation::REFERENCE, op.type() == ClipPathOperation::REFERENCE); -class ShapeClipPathOperation : public ClipPathOperation { +class ShapeClipPathOperation FINAL : public ClipPathOperation { public: static PassRefPtr<ShapeClipPathOperation> create(PassRefPtr<BasicShape> shape) { @@ -111,10 +111,7 @@ public: } private: - virtual bool operator==(const ClipPathOperation& o) const OVERRIDE - { - return isSameType(o) && m_shape == static_cast<const ShapeClipPathOperation&>(o).m_shape; - } + virtual bool operator==(const ClipPathOperation&) const OVERRIDE; ShapeClipPathOperation(PassRefPtr<BasicShape> shape) : ClipPathOperation(SHAPE) @@ -128,6 +125,11 @@ private: DEFINE_TYPE_CASTS(ShapeClipPathOperation, ClipPathOperation, op, op->type() == ClipPathOperation::SHAPE, op.type() == ClipPathOperation::SHAPE); +inline bool ShapeClipPathOperation::operator==(const ClipPathOperation& o) const +{ + return isSameType(o) && *m_shape == *toShapeClipPathOperation(o).m_shape; +} + } #endif // ClipPathOperation_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/ClipRect.h b/chromium/third_party/WebKit/Source/core/rendering/ClipRect.h index 8fbcebf90a6..b0bed95bb77 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/ClipRect.h +++ b/chromium/third_party/WebKit/Source/core/rendering/ClipRect.h @@ -179,6 +179,7 @@ private: enum ClipRectsType { PaintingClipRects, // Relative to painting ancestor. Used for painting. RootRelativeClipRects, // Relative to the ancestor treated as the root (e.g. transformed layer). Used for hit testing. + CompositingClipRects, // Relative to the compositing ancestor. Used for updating graphics layer geometry. AbsoluteClipRects, // Relative to the RenderView's layer. Used for compositing overlap testing. NumCachedClipRectsTypes, AllClipRectTypes, @@ -195,19 +196,24 @@ struct ClipRectsCache { public: ClipRectsCache() { -#ifndef NDEBUG for (int i = 0; i < NumCachedClipRectsTypes; ++i) { m_clipRectsRoot[i] = 0; +#ifndef NDEBUG m_scrollbarRelevancy[i] = IgnoreOverlayScrollbarSize; - } #endif + } } PassRefPtr<ClipRects> getClipRects(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow) { return m_clipRects[getIndex(clipRectsType, respectOverflow)]; } - void setClipRects(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow, PassRefPtr<ClipRects> clipRects) { m_clipRects[getIndex(clipRectsType, respectOverflow)] = clipRects; } + void setClipRects(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow, PassRefPtr<ClipRects> clipRects, const RenderLayer* root) + { + m_clipRects[getIndex(clipRectsType, respectOverflow)] = clipRects; + m_clipRectsRoot[clipRectsType] = root; + } + + const RenderLayer* clipRectsRoot(ClipRectsType clipRectsType) const { return m_clipRectsRoot[clipRectsType]; } #ifndef NDEBUG - const RenderLayer* m_clipRectsRoot[NumCachedClipRectsTypes]; OverlayScrollbarSizeRelevancy m_scrollbarRelevancy[NumCachedClipRectsTypes]; #endif @@ -220,6 +226,7 @@ private: return index; } + const RenderLayer* m_clipRectsRoot[NumCachedClipRectsTypes]; RefPtr<ClipRects> m_clipRects[NumCachedClipRectsTypes * 2]; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/ColumnInfo.h b/chromium/third_party/WebKit/Source/core/rendering/ColumnInfo.h index 39722819249..ddad54e1593 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/ColumnInfo.h +++ b/chromium/third_party/WebKit/Source/core/rendering/ColumnInfo.h @@ -38,14 +38,12 @@ public: : m_desiredColumnWidth(0) , m_desiredColumnCount(1) , m_progressionAxis(InlineAxis) - , m_progressionIsReversed(false) , m_columnCount(1) , m_columnHeight(0) , m_minimumColumnHeight(0) , m_forcedBreaks(0) , m_maximumDistanceBetweenForcedBreaks(0) , m_forcedBreakOffset(0) - , m_paginationUnit(Column) { } @@ -60,9 +58,6 @@ public: Axis progressionAxis() const { return m_progressionAxis; } void setProgressionAxis(Axis progressionAxis) { m_progressionAxis = progressionAxis; } - bool progressionIsReversed() const { return m_progressionIsReversed; } - void setProgressionIsReversed(bool reversed) { m_progressionIsReversed = reversed; } - unsigned columnCount() const { return m_columnCount; } LayoutUnit columnHeight() const { return m_columnHeight; } @@ -98,15 +93,10 @@ public: m_forcedBreakOffset = offsetFromFirstPage; } - enum PaginationUnit { Column, Page }; - PaginationUnit paginationUnit() const { return m_paginationUnit; } - void setPaginationUnit(PaginationUnit paginationUnit) { m_paginationUnit = paginationUnit; } - private: LayoutUnit m_desiredColumnWidth; unsigned m_desiredColumnCount; Axis m_progressionAxis; - bool m_progressionIsReversed; unsigned m_columnCount; LayoutUnit m_columnHeight; @@ -114,7 +104,6 @@ private: int m_forcedBreaks; // FIXME: We will ultimately need to cache more information to balance around forced breaks properly. LayoutUnit m_maximumDistanceBetweenForcedBreaks; LayoutUnit m_forcedBreakOffset; - PaginationUnit m_paginationUnit; }; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/CompositedLayerMapping.cpp b/chromium/third_party/WebKit/Source/core/rendering/CompositedLayerMapping.cpp deleted file mode 100644 index 3358f9b4ced..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/CompositedLayerMapping.cpp +++ /dev/null @@ -1,2228 +0,0 @@ -/* - * Copyright (C) 2009, 2010, 2011 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 "core/rendering/CompositedLayerMapping.h" - -#include "CSSPropertyNames.h" -#include "HTMLNames.h" -#include "RuntimeEnabledFeatures.h" -#include "core/animation/ActiveAnimations.h" -#include "core/fetch/ImageResource.h" -#include "core/html/HTMLIFrameElement.h" -#include "core/html/HTMLMediaElement.h" -#include "core/html/canvas/CanvasRenderingContext.h" -#include "core/inspector/InspectorInstrumentation.h" -#include "core/page/Chrome.h" -#include "core/frame/FrameView.h" -#include "core/frame/Settings.h" -#include "core/frame/animation/AnimationController.h" -#include "core/page/scrolling/ScrollingCoordinator.h" -#include "core/plugins/PluginView.h" -#include "core/rendering/FilterEffectRenderer.h" -#include "core/rendering/RenderApplet.h" -#include "core/rendering/RenderEmbeddedObject.h" -#include "core/rendering/RenderIFrame.h" -#include "core/rendering/RenderImage.h" -#include "core/rendering/RenderLayerCompositor.h" -#include "core/rendering/RenderLayerStackingNodeIterator.h" -#include "core/rendering/RenderVideo.h" -#include "core/rendering/RenderView.h" -#include "core/rendering/animation/WebAnimationProvider.h" -#include "core/rendering/style/KeyframeList.h" -#include "platform/LengthFunctions.h" -#include "platform/fonts/FontCache.h" -#include "platform/graphics/GraphicsContext.h" -#include "platform/graphics/GraphicsContext3D.h" -#include "platform/graphics/filters/custom/CustomFilterOperation.h" -#include "wtf/CurrentTime.h" -#include "wtf/text/StringBuilder.h" - -using namespace std; - -namespace WebCore { - -using namespace HTMLNames; - -static IntRect clipBox(RenderBox* renderer); - -static IntRect contentsRect(const RenderObject* renderer) -{ - if (!renderer->isBox()) - return IntRect(); - - return renderer->isVideo() ? - toRenderVideo(renderer)->videoBox() : - pixelSnappedIntRect(toRenderBox(renderer)->contentBoxRect()); -} - -static IntRect backgroundRect(const RenderObject* renderer) -{ - if (!renderer->isBox()) - return IntRect(); - - LayoutRect rect; - const RenderBox* box = toRenderBox(renderer); - EFillBox clip = box->style()->backgroundClip(); - switch (clip) { - case BorderFillBox: - rect = box->borderBoxRect(); - break; - case PaddingFillBox: - rect = box->paddingBoxRect(); - break; - case ContentFillBox: - rect = box->contentBoxRect(); - break; - case TextFillBox: - break; - } - - return pixelSnappedIntRect(rect); -} - -static inline bool isAcceleratedCanvas(const RenderObject* renderer) -{ - if (renderer->isCanvas()) { - HTMLCanvasElement* canvas = toHTMLCanvasElement(renderer->node()); - if (CanvasRenderingContext* context = canvas->renderingContext()) - return context->isAccelerated(); - } - return false; -} - -static bool hasBoxDecorations(const RenderStyle* style) -{ - return style->hasBorder() || style->hasBorderRadius() || style->hasOutline() || style->hasAppearance() || style->boxShadow() || style->hasFilter(); -} - -static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle* style) -{ - return hasBoxDecorations(style) || style->hasBackgroundImage(); -} - -static bool contentLayerSupportsDirectBackgroundComposition(const RenderObject* renderer) -{ - // No support for decorations - border, border-radius or outline. - // Only simple background - solid color or transparent. - if (hasBoxDecorationsOrBackgroundImage(renderer->style())) - return false; - - // If there is no background, there is nothing to support. - if (!renderer->style()->hasBackground()) - return true; - - // Simple background that is contained within the contents rect. - return contentsRect(renderer).contains(backgroundRect(renderer)); -} - -static inline bool isAcceleratedContents(RenderObject* renderer) -{ - return isAcceleratedCanvas(renderer) - || (renderer->isEmbeddedObject() && toRenderEmbeddedObject(renderer)->allowsAcceleratedCompositing()) - || renderer->isVideo(); -} - -// Get the scrolling coordinator in a way that works inside CompositedLayerMapping's destructor. -static ScrollingCoordinator* scrollingCoordinatorFromLayer(RenderLayer* layer) -{ - Page* page = layer->renderer()->frame()->page(); - if (!page) - return 0; - - return page->scrollingCoordinator(); -} - -CompositedLayerMapping::CompositedLayerMapping(RenderLayer* layer) - : m_owningLayer(layer) - , m_animationProvider(adoptPtr(new WebAnimationProvider)) - , m_artificiallyInflatedBounds(false) - , m_boundsConstrainedByClipping(false) - , m_isMainFrameRenderViewLayer(false) - , m_requiresOwnBackingStoreForIntrinsicReasons(true) - , m_requiresOwnBackingStoreForAncestorReasons(true) - , m_canCompositeFilters(false) - , m_backgroundLayerPaintsFixedRootBackground(false) -{ - if (layer->isRootLayer() && renderer()->frame()->isMainFrame()) - m_isMainFrameRenderViewLayer = true; - - createPrimaryGraphicsLayer(); -} - -CompositedLayerMapping::~CompositedLayerMapping() -{ - // Do not leave the destroyed pointer dangling on any RenderLayers that painted to this mapping's squashing layer. - for (size_t i = 0; i < m_squashedLayers.size(); ++i) { - if (m_squashedLayers[i].renderLayer->groupedMapping() == this) - m_squashedLayers[i].renderLayer->setGroupedMapping(0); - } - - updateClippingLayers(false, false); - updateOverflowControlsLayers(false, false, false); - updateForegroundLayer(false); - updateBackgroundLayer(false); - updateMaskLayer(false); - updateClippingMaskLayers(false); - updateScrollingLayers(false); - updateSquashingLayers(false); - destroyGraphicsLayers(); -} - -PassOwnPtr<GraphicsLayer> CompositedLayerMapping::createGraphicsLayer(CompositingReasons reasons) -{ - GraphicsLayerFactory* graphicsLayerFactory = 0; - if (Page* page = renderer()->frame()->page()) - graphicsLayerFactory = page->chrome().client().graphicsLayerFactory(); - - OwnPtr<GraphicsLayer> graphicsLayer = GraphicsLayer::create(graphicsLayerFactory, this); - - graphicsLayer->setCompositingReasons(reasons); - - return graphicsLayer.release(); -} - -void CompositedLayerMapping::createPrimaryGraphicsLayer() -{ - m_graphicsLayer = createGraphicsLayer(m_owningLayer->compositingReasons()); - -#if !OS(ANDROID) - if (m_isMainFrameRenderViewLayer) - m_graphicsLayer->contentLayer()->setDrawCheckerboardForMissingTiles(true); -#endif - - updateOpacity(renderer()->style()); - updateTransform(renderer()->style()); - updateFilters(renderer()->style()); - - if (RuntimeEnabledFeatures::cssCompositingEnabled()) { - updateLayerBlendMode(renderer()->style()); - updateIsRootForIsolatedGroup(); - } -} - -void CompositedLayerMapping::destroyGraphicsLayers() -{ - if (m_graphicsLayer) - m_graphicsLayer->removeFromParent(); - - m_ancestorClippingLayer = nullptr; - m_graphicsLayer = nullptr; - m_foregroundLayer = nullptr; - m_backgroundLayer = nullptr; - m_childContainmentLayer = nullptr; - m_maskLayer = nullptr; - m_childClippingMaskLayer = nullptr; - - m_scrollingLayer = nullptr; - m_scrollingContentsLayer = nullptr; -} - -void CompositedLayerMapping::updateOpacity(const RenderStyle* style) -{ - m_graphicsLayer->setOpacity(compositingOpacity(style->opacity())); -} - -void CompositedLayerMapping::updateTransform(const RenderStyle* style) -{ - // FIXME: This could use m_owningLayer->transform(), but that currently has transform-origin - // baked into it, and we don't want that. - TransformationMatrix t; - if (m_owningLayer->hasTransform()) { - style->applyTransform(t, toRenderBox(renderer())->pixelSnappedBorderBoxRect().size(), RenderStyle::ExcludeTransformOrigin); - makeMatrixRenderable(t, compositor()->canRender3DTransforms()); - } - - m_graphicsLayer->setTransform(t); -} - -void CompositedLayerMapping::updateFilters(const RenderStyle* style) -{ - bool didCompositeFilters = m_canCompositeFilters; - m_canCompositeFilters = m_graphicsLayer->setFilters(owningLayer()->computeFilterOperations(style)); - if (didCompositeFilters != m_canCompositeFilters) { - // - // If filters used to be painted in software and are now painted in the compositor, we need to: - // (1) Remove the FilterEffectRenderer, which was used for painting filters in software. - // (2) Repaint the layer contents to remove the software-applied filter because the compositor will apply it. - // - // Similarly, if filters used to be painted in the compositor and are now painted in software, we need to: - // (1) Create a FilterEffectRenderer. - // (2) Repaint the layer contents to apply a software filter because the compositor won't apply it. - // - m_owningLayer->updateOrRemoveFilterEffectRenderer(); - setContentsNeedDisplay(); - } -} - -void CompositedLayerMapping::updateLayerBlendMode(const RenderStyle* style) -{ - setBlendMode(style->blendMode()); -} - -void CompositedLayerMapping::updateIsRootForIsolatedGroup() -{ - bool isolate = m_owningLayer->shouldIsolateCompositedDescendants(); - - // non stacking context layers should never isolate - ASSERT(m_owningLayer->stackingNode()->isStackingContext() || !isolate); - - m_graphicsLayer->setIsRootForIsolatedGroup(isolate); -} - -void CompositedLayerMapping::updateContentsOpaque() -{ - // For non-root layers, background is always painted by the primary graphics layer. - ASSERT(m_isMainFrameRenderViewLayer || !m_backgroundLayer); - if (m_backgroundLayer) { - m_graphicsLayer->setContentsOpaque(false); - m_backgroundLayer->setContentsOpaque(m_owningLayer->backgroundIsKnownToBeOpaqueInRect(compositedBounds())); - } else { - m_graphicsLayer->setContentsOpaque(m_owningLayer->backgroundIsKnownToBeOpaqueInRect(compositedBounds())); - } -} - -static bool hasNonZeroTransformOrigin(const RenderObject* renderer) -{ - RenderStyle* style = renderer->style(); - return (style->transformOriginX().type() == Fixed && style->transformOriginX().value()) - || (style->transformOriginY().type() == Fixed && style->transformOriginY().value()); -} - -static bool layerOrAncestorIsTransformedOrUsingCompositedScrolling(RenderLayer* layer) -{ - for (RenderLayer* curr = layer; curr; curr = curr->parent()) { - if (curr->hasTransform() || curr->needsCompositedScrolling()) - return true; - } - - return false; -} - -bool CompositedLayerMapping::shouldClipCompositedBounds() const -{ - // Scrollbar layers use this layer for relative positioning, so don't clip. - if (layerForHorizontalScrollbar() || layerForVerticalScrollbar()) - return false; - - if (layerOrAncestorIsTransformedOrUsingCompositedScrolling(m_owningLayer)) - return false; - - // Scrolled composited layers are clipped by their ancestor clipping layer, - // so don't clip these, either. - bool hasAncestorClippingLayer = compositor()->clippedByAncestor(m_owningLayer); - bool clippingAncestorIsScrollParent = m_owningLayer->renderer()->containingBlock()->enclosingLayer() == m_owningLayer->ancestorScrollingLayer(); - if (hasAncestorClippingLayer && clippingAncestorIsScrollParent) - return false; - - return true; -} - -void CompositedLayerMapping::updateCompositedBounds() -{ - // We need to know if we draw content in order to update our bounds (this has an effect - // on whether or not descendands will paint into our backing). Update this value now. - updateDrawsContent(isSimpleContainerCompositingLayer()); - - IntRect layerBounds = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer); - - // Clip to the size of the document or enclosing overflow-scroll layer. - // If this or an ancestor is transformed, we can't currently compute the correct rect to intersect with. - // We'd need RenderObject::convertContainerToLocalQuad(), which doesn't yet exist. - if (shouldClipCompositedBounds()) { - RenderView* view = m_owningLayer->renderer()->view(); - RenderLayer* rootLayer = view->layer(); - - LayoutRect clippingBounds; - if (renderer()->style()->position() == FixedPosition && renderer()->container() == view) - clippingBounds = view->frameView()->viewportConstrainedVisibleContentRect(); - else - clippingBounds = view->unscaledDocumentRect(); - - if (m_owningLayer != rootLayer) - clippingBounds.intersect(m_owningLayer->backgroundClipRect(ClipRectsContext(rootLayer, 0, AbsoluteClipRects)).rect()); // FIXME: Incorrect for CSS regions. - - LayoutPoint delta; - m_owningLayer->convertToLayerCoords(rootLayer, delta); - clippingBounds.move(-delta.x(), -delta.y()); - - layerBounds.intersect(pixelSnappedIntRect(clippingBounds)); - m_boundsConstrainedByClipping = true; - } else { - m_boundsConstrainedByClipping = false; - } - - // If the element has a transform-origin that has fixed lengths, and the renderer has zero size, - // then we need to ensure that the compositing layer has non-zero size so that we can apply - // the transform-origin via the GraphicsLayer anchorPoint (which is expressed as a fractional value). - if (layerBounds.isEmpty() && hasNonZeroTransformOrigin(renderer())) { - layerBounds.setWidth(1); - layerBounds.setHeight(1); - m_artificiallyInflatedBounds = true; - } else { - m_artificiallyInflatedBounds = false; - } - - setCompositedBounds(layerBounds); -} - -void CompositedLayerMapping::updateAfterWidgetResize() -{ - if (renderer()->isRenderPart()) { - if (RenderLayerCompositor* innerCompositor = RenderLayerCompositor::frameContentsCompositor(toRenderPart(renderer()))) { - innerCompositor->frameViewDidChangeSize(); - innerCompositor->frameViewDidChangeLocation(contentsBox().location()); - } - } -} - -void CompositedLayerMapping::updateCompositingReasons() -{ - // All other layers owned by this mapping will have the same compositing reason - // for their lifetime, so they are initialized only when created. - m_graphicsLayer->setCompositingReasons(m_owningLayer->compositingReasons()); -} - -void CompositedLayerMapping::updateAfterLayout(UpdateAfterLayoutFlags flags) -{ - RenderLayerCompositor* layerCompositor = compositor(); - if (!layerCompositor->compositingLayersNeedRebuild()) { - // Calling updateGraphicsLayerGeometry() here gives incorrect results, because the - // position of this layer's GraphicsLayer depends on the position of our compositing - // ancestor's GraphicsLayer. That cannot be determined until all the descendant - // RenderLayers of that ancestor have been processed via updateLayerPositions(). - // - // The solution is to update compositing children of this layer here, - // via updateCompositingChildrenGeometry(). - updateCompositedBounds(); - layerCompositor->updateCompositingDescendantGeometry(m_owningLayer->stackingNode(), m_owningLayer, flags & CompositingChildrenOnly); - - if (flags & IsUpdateRoot) { - updateGraphicsLayerGeometry(); - layerCompositor->updateRootLayerPosition(); - RenderLayerStackingNode* stackingContainer = m_owningLayer->stackingNode()->enclosingStackingContainerNode(); - if (!layerCompositor->compositingLayersNeedRebuild() && stackingContainer && (stackingContainer != m_owningLayer->stackingNode())) - layerCompositor->updateCompositingDescendantGeometry(stackingContainer, stackingContainer->layer(), flags & CompositingChildrenOnly); - } - } - - if (flags & NeedsFullRepaint && !paintsIntoCompositedAncestor()) - setContentsNeedDisplay(); -} - -bool CompositedLayerMapping::updateGraphicsLayerConfiguration() -{ - RenderLayerCompositor* compositor = this->compositor(); - RenderObject* renderer = this->renderer(); - - m_owningLayer->updateDescendantDependentFlags(); - m_owningLayer->stackingNode()->updateZOrderLists(); - - bool layerConfigChanged = false; - setBackgroundLayerPaintsFixedRootBackground(compositor->needsFixedRootBackgroundLayer(m_owningLayer)); - - // The background layer is currently only used for fixed root backgrounds. - if (updateBackgroundLayer(m_backgroundLayerPaintsFixedRootBackground)) - layerConfigChanged = true; - - if (updateForegroundLayer(compositor->needsContentsCompositingLayer(m_owningLayer))) - layerConfigChanged = true; - - bool needsDescendentsClippingLayer = compositor->clipsCompositingDescendants(m_owningLayer); - - // Our scrolling layer will clip. - if (m_owningLayer->needsCompositedScrolling()) - needsDescendentsClippingLayer = false; - - RenderLayer* scrollParent = m_owningLayer->scrollParent(); - bool needsAncestorClip = compositor->clippedByAncestor(m_owningLayer); - if (scrollParent) { - // If our containing block is our ancestor scrolling layer, then we'll already be clipped - // to it via our scroll parent and we don't need an ancestor clipping layer. - if (m_owningLayer->renderer()->containingBlock()->enclosingLayer() == m_owningLayer->ancestorCompositedScrollingLayer()) - needsAncestorClip = false; - } - if (updateClippingLayers(needsAncestorClip, needsDescendentsClippingLayer)) - layerConfigChanged = true; - - if (updateOverflowControlsLayers(requiresHorizontalScrollbarLayer(), requiresVerticalScrollbarLayer(), requiresScrollCornerLayer())) - layerConfigChanged = true; - - if (updateScrollingLayers(m_owningLayer->needsCompositedScrolling())) - layerConfigChanged = true; - - updateScrollParent(scrollParent); - updateClipParent(m_owningLayer->clipParent()); - - if (updateSquashingLayers(!m_squashedLayers.isEmpty())) - layerConfigChanged = true; - - if (layerConfigChanged) - updateInternalHierarchy(); - - if (updateMaskLayer(renderer->hasMask())) - m_graphicsLayer->setMaskLayer(m_maskLayer.get()); - - bool hasChildClippingLayer = compositor->clipsCompositingDescendants(m_owningLayer) && (hasClippingLayer() || hasScrollingLayer()); - bool needsChildClippingMask = (renderer->style()->clipPath() || renderer->style()->hasBorderRadius()) && (hasChildClippingLayer || isAcceleratedContents(renderer)); - if (updateClippingMaskLayers(needsChildClippingMask)) { - if (hasClippingLayer()) - clippingLayer()->setMaskLayer(m_childClippingMaskLayer.get()); - else if (hasScrollingLayer()) - scrollingLayer()->setMaskLayer(m_childClippingMaskLayer.get()); - else if (isAcceleratedContents(renderer)) - m_graphicsLayer->setContentsClippingMaskLayer(m_childClippingMaskLayer.get()); - } - - if (m_owningLayer->reflectionInfo()) { - if (m_owningLayer->reflectionInfo()->reflectionLayer()->hasCompositedLayerMapping()) { - GraphicsLayer* reflectionLayer = m_owningLayer->reflectionInfo()->reflectionLayer()->compositedLayerMapping()->mainGraphicsLayer(); - m_graphicsLayer->setReplicatedByLayer(reflectionLayer); - } - } else { - m_graphicsLayer->setReplicatedByLayer(0); - } - - updateBackgroundColor(isSimpleContainerCompositingLayer()); - - if (isDirectlyCompositedImage()) - updateImageContents(); - - if (renderer->isEmbeddedObject() && toRenderEmbeddedObject(renderer)->allowsAcceleratedCompositing()) { - PluginView* pluginView = toPluginView(toRenderWidget(renderer)->widget()); - m_graphicsLayer->setContentsToPlatformLayer(pluginView->platformLayer()); - } else if (renderer->node() && renderer->node()->isFrameOwnerElement() && toHTMLFrameOwnerElement(renderer->node())->contentFrame()) { - blink::WebLayer* layer = toHTMLFrameOwnerElement(renderer->node())->contentFrame()->remotePlatformLayer(); - if (layer) - m_graphicsLayer->setContentsToPlatformLayer(layer); - } else if (renderer->isVideo()) { - HTMLMediaElement* mediaElement = toHTMLMediaElement(renderer->node()); - m_graphicsLayer->setContentsToPlatformLayer(mediaElement->platformLayer()); - } else if (isAcceleratedCanvas(renderer)) { - HTMLCanvasElement* canvas = toHTMLCanvasElement(renderer->node()); - if (CanvasRenderingContext* context = canvas->renderingContext()) - m_graphicsLayer->setContentsToPlatformLayer(context->platformLayer()); - layerConfigChanged = true; - } - if (renderer->isRenderPart()) - layerConfigChanged = RenderLayerCompositor::parentFrameContentLayers(toRenderPart(renderer)); - - return layerConfigChanged; -} - -static IntRect clipBox(RenderBox* renderer) -{ - LayoutRect result = PaintInfo::infiniteRect(); - if (renderer->hasOverflowClip()) - result = renderer->overflowClipRect(LayoutPoint(), 0); // FIXME: Incorrect for CSS regions. - - if (renderer->hasClip()) - result.intersect(renderer->clipRect(LayoutPoint(), 0)); // FIXME: Incorrect for CSS regions. - - return pixelSnappedIntRect(result); -} - -void CompositedLayerMapping::updateGraphicsLayerGeometry() -{ - // If we haven't built z-order lists yet, wait until later. - if (m_owningLayer->stackingNode()->isStackingContainer() && m_owningLayer->stackingNode()->zOrderListsDirty()) - return; - - // Set transform property, if it is not animating. We have to do this here because the transform - // is affected by the layer dimensions. - if (RuntimeEnabledFeatures::webAnimationsCSSEnabled() - ? !hasActiveAnimationsOnCompositor(*renderer(), CSSPropertyWebkitTransform) - : !renderer()->animation().isRunningAcceleratedAnimationOnRenderer(renderer(), CSSPropertyWebkitTransform)) - updateTransform(renderer()->style()); - - // Set opacity, if it is not animating. - if (RuntimeEnabledFeatures::webAnimationsCSSEnabled() - ? !hasActiveAnimationsOnCompositor(*renderer(), CSSPropertyOpacity) - : !renderer()->animation().isRunningAcceleratedAnimationOnRenderer(renderer(), CSSPropertyOpacity)) - updateOpacity(renderer()->style()); - - bool isSimpleContainer = isSimpleContainerCompositingLayer(); - - m_owningLayer->updateDescendantDependentFlags(); - - // m_graphicsLayer is the corresponding GraphicsLayer for this RenderLayer and its non-compositing - // descendants. So, the visibility flag for m_graphicsLayer should be true if there are any - // non-compositing visible layers. - bool contentsVisible = m_owningLayer->hasVisibleContent() || hasVisibleNonCompositingDescendantLayers(); - if (RuntimeEnabledFeatures::overlayFullscreenVideoEnabled() && renderer()->isVideo()) { - HTMLMediaElement* mediaElement = toHTMLMediaElement(renderer()->node()); - if (mediaElement->isFullscreen()) - contentsVisible = false; - } - m_graphicsLayer->setContentsVisible(contentsVisible); - - RenderStyle* style = renderer()->style(); - // FIXME: reflections should force transform-style to be flat in the style: https://bugs.webkit.org/show_bug.cgi?id=106959 - bool preserves3D = style->transformStyle3D() == TransformStyle3DPreserve3D && !renderer()->hasReflection(); - m_graphicsLayer->setPreserves3D(preserves3D); - m_graphicsLayer->setBackfaceVisibility(style->backfaceVisibility() == BackfaceVisibilityVisible); - - RenderLayer* compAncestor = m_owningLayer->ancestorCompositingLayer(); - - // We compute everything relative to the enclosing compositing layer. - IntRect ancestorCompositingBounds; - if (compAncestor) { - ASSERT(compAncestor->hasCompositedLayerMapping()); - ancestorCompositingBounds = pixelSnappedIntRect(compAncestor->compositedLayerMapping()->compositedBounds()); - } - - IntRect localCompositingBounds = pixelSnappedIntRect(compositedBounds()); - - IntRect relativeCompositingBounds(localCompositingBounds); - IntPoint delta; - m_owningLayer->convertToPixelSnappedLayerCoords(compAncestor, delta); - relativeCompositingBounds.moveBy(delta); - - IntPoint graphicsLayerParentLocation; - if (compAncestor && compAncestor->compositedLayerMapping()->hasClippingLayer()) { - // If the compositing ancestor has a layer to clip children, we parent in that, and therefore - // position relative to it. - IntRect clippingBox = clipBox(toRenderBox(compAncestor->renderer())); - graphicsLayerParentLocation = clippingBox.location(); - } else if (compAncestor) { - graphicsLayerParentLocation = ancestorCompositingBounds.location(); - } else { - graphicsLayerParentLocation = renderer()->view()->documentRect().location(); - } - - if (compAncestor && compAncestor->needsCompositedScrolling()) { - RenderBox* renderBox = toRenderBox(compAncestor->renderer()); - IntSize scrollOffset = renderBox->scrolledContentOffset(); - IntPoint scrollOrigin(renderBox->borderLeft(), renderBox->borderTop()); - graphicsLayerParentLocation = scrollOrigin - scrollOffset; - } - - if (compAncestor && m_ancestorClippingLayer) { - // Call calculateRects to get the backgroundRect which is what is used to clip the contents of this - // layer. Note that we call it with temporaryClipRects = true because normally when computing clip rects - // for a compositing layer, rootLayer is the layer itself. - ClipRectsContext clipRectsContext(compAncestor, 0, TemporaryClipRects, IgnoreOverlayScrollbarSize, IgnoreOverflowClip); - IntRect parentClipRect = pixelSnappedIntRect(m_owningLayer->backgroundClipRect(clipRectsContext).rect()); // FIXME: Incorrect for CSS regions. - ASSERT(parentClipRect != PaintInfo::infiniteRect()); - m_ancestorClippingLayer->setPosition(FloatPoint(parentClipRect.location() - graphicsLayerParentLocation)); - m_ancestorClippingLayer->setSize(parentClipRect.size()); - - // backgroundRect is relative to compAncestor, so subtract deltaX/deltaY to get back to local coords. - m_ancestorClippingLayer->setOffsetFromRenderer(parentClipRect.location() - delta); - - // The primary layer is then parented in, and positioned relative to this clipping layer. - graphicsLayerParentLocation = parentClipRect.location(); - } - - FloatSize contentsSize = relativeCompositingBounds.size(); - - m_graphicsLayer->setPosition(FloatPoint(relativeCompositingBounds.location() - graphicsLayerParentLocation)); - m_graphicsLayer->setOffsetFromRenderer(toIntSize(localCompositingBounds.location())); - - FloatSize oldSize = m_graphicsLayer->size(); - if (oldSize != contentsSize) { - m_graphicsLayer->setSize(contentsSize); - // Usually invalidation will happen via layout etc, but if we've affected the layer - // size by constraining relative to a clipping ancestor or the viewport, we - // have to invalidate to avoid showing stretched content. - if (m_boundsConstrainedByClipping) - m_graphicsLayer->setNeedsDisplay(); - } - - // If we have a layer that clips children, position it. - IntRect clippingBox; - if (GraphicsLayer* clipLayer = clippingLayer()) { - clippingBox = clipBox(toRenderBox(renderer())); - clipLayer->setPosition(FloatPoint(clippingBox.location() - localCompositingBounds.location())); - clipLayer->setSize(clippingBox.size()); - clipLayer->setOffsetFromRenderer(toIntSize(clippingBox.location())); - if (m_childClippingMaskLayer && !m_scrollingLayer) { - m_childClippingMaskLayer->setPosition(clipLayer->position()); - m_childClippingMaskLayer->setSize(clipLayer->size()); - m_childClippingMaskLayer->setOffsetFromRenderer(clipLayer->offsetFromRenderer()); - } - } - - if (m_maskLayer) { - if (m_maskLayer->size() != m_graphicsLayer->size()) { - m_maskLayer->setSize(m_graphicsLayer->size()); - m_maskLayer->setNeedsDisplay(); - } - m_maskLayer->setPosition(FloatPoint()); - m_maskLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer()); - } - - if (m_owningLayer->hasTransform()) { - const IntRect borderBox = toRenderBox(renderer())->pixelSnappedBorderBoxRect(); - - // Get layout bounds in the coords of compAncestor to match relativeCompositingBounds. - IntRect layerBounds = IntRect(delta, borderBox.size()); - - // Update properties that depend on layer dimensions - FloatPoint3D transformOrigin = computeTransformOrigin(borderBox); - // Compute the anchor point, which is in the center of the renderer box unless transform-origin is set. - FloatPoint3D anchor(relativeCompositingBounds.width() != 0.0f ? ((layerBounds.x() - relativeCompositingBounds.x()) + transformOrigin.x()) / relativeCompositingBounds.width() : 0.5f, - relativeCompositingBounds.height() != 0.0f ? ((layerBounds.y() - relativeCompositingBounds.y()) + transformOrigin.y()) / relativeCompositingBounds.height() : 0.5f, - transformOrigin.z()); - m_graphicsLayer->setAnchorPoint(anchor); - - RenderStyle* style = renderer()->style(); - GraphicsLayer* clipLayer = clippingLayer(); - if (style->hasPerspective()) { - TransformationMatrix t = owningLayer()->perspectiveTransform(); - - if (clipLayer) { - clipLayer->setChildrenTransform(t); - m_graphicsLayer->setChildrenTransform(TransformationMatrix()); - } else { - m_graphicsLayer->setChildrenTransform(t); - } - } else { - if (clipLayer) - clipLayer->setChildrenTransform(TransformationMatrix()); - else - m_graphicsLayer->setChildrenTransform(TransformationMatrix()); - } - } else { - m_graphicsLayer->setAnchorPoint(FloatPoint3D(0.5f, 0.5f, 0)); - } - - if (m_foregroundLayer) { - FloatPoint foregroundPosition; - FloatSize foregroundSize = contentsSize; - IntSize foregroundOffset = m_graphicsLayer->offsetFromRenderer(); - if (hasClippingLayer()) { - // If we have a clipping layer (which clips descendants), then the foreground layer is a child of it, - // so that it gets correctly sorted with children. In that case, position relative to the clipping layer. - foregroundSize = FloatSize(clippingBox.size()); - foregroundOffset = toIntSize(clippingBox.location()); - } - - m_foregroundLayer->setPosition(foregroundPosition); - if (foregroundSize != m_foregroundLayer->size()) { - m_foregroundLayer->setSize(foregroundSize); - m_foregroundLayer->setNeedsDisplay(); - } - m_foregroundLayer->setOffsetFromRenderer(foregroundOffset); - } - - if (m_backgroundLayer) { - FloatPoint backgroundPosition; - FloatSize backgroundSize = contentsSize; - if (backgroundLayerPaintsFixedRootBackground()) { - FrameView* frameView = toRenderView(renderer())->frameView(); - backgroundSize = frameView->visibleContentRect().size(); - } - m_backgroundLayer->setPosition(backgroundPosition); - if (backgroundSize != m_backgroundLayer->size()) { - m_backgroundLayer->setSize(backgroundSize); - m_backgroundLayer->setNeedsDisplay(); - } - m_backgroundLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer()); - } - - if (m_owningLayer->reflectionInfo() && m_owningLayer->reflectionInfo()->reflectionLayer()->hasCompositedLayerMapping()) { - CompositedLayerMappingPtr reflectionCompositedLayerMapping = m_owningLayer->reflectionInfo()->reflectionLayer()->compositedLayerMapping(); - reflectionCompositedLayerMapping->updateGraphicsLayerGeometry(); - - // The reflection layer has the bounds of m_owningLayer->reflectionLayer(), - // but the reflected layer is the bounds of this layer, so we need to position it appropriately. - FloatRect layerBounds = compositedBounds(); - FloatRect reflectionLayerBounds = reflectionCompositedLayerMapping->compositedBounds(); - reflectionCompositedLayerMapping->mainGraphicsLayer()->setReplicatedLayerPosition(FloatPoint(layerBounds.location() - reflectionLayerBounds.location())); - } - - if (m_scrollingLayer) { - ASSERT(m_scrollingContentsLayer); - RenderBox* renderBox = toRenderBox(renderer()); - IntRect clientBox = enclosingIntRect(renderBox->clientBoxRect()); - // FIXME: We should make RenderBox::clientBoxRect consider scrollbar placement. - if (style->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) - clientBox.move(renderBox->verticalScrollbarWidth(), 0); - - IntSize adjustedScrollOffset = m_owningLayer->scrollableArea()->adjustedScrollOffset(); - m_scrollingLayer->setPosition(FloatPoint(clientBox.location() - localCompositingBounds.location())); - m_scrollingLayer->setSize(clientBox.size()); - - IntSize oldScrollingLayerOffset = m_scrollingLayer->offsetFromRenderer(); - m_scrollingLayer->setOffsetFromRenderer(-toIntSize(clientBox.location())); - - if (m_childClippingMaskLayer) { - m_childClippingMaskLayer->setPosition(m_scrollingLayer->position()); - m_childClippingMaskLayer->setSize(m_scrollingLayer->size()); - m_childClippingMaskLayer->setOffsetFromRenderer(toIntSize(clientBox.location())); - } - - bool clientBoxOffsetChanged = oldScrollingLayerOffset != m_scrollingLayer->offsetFromRenderer(); - - IntSize scrollSize(renderBox->scrollWidth(), renderBox->scrollHeight()); - if (scrollSize != m_scrollingContentsLayer->size() || clientBoxOffsetChanged) - m_scrollingContentsLayer->setNeedsDisplay(); - - IntSize scrollingContentsOffset = toIntSize(clientBox.location() - adjustedScrollOffset); - if (scrollingContentsOffset != m_scrollingContentsLayer->offsetFromRenderer() || scrollSize != m_scrollingContentsLayer->size()) { - bool scrollingCoordinatorHandlesOffset = compositor()->scrollingLayerDidChange(m_owningLayer); - - if (scrollingCoordinatorHandlesOffset) - m_scrollingContentsLayer->setPosition(-m_owningLayer->scrollableArea()->scrollOrigin()); - else - m_scrollingContentsLayer->setPosition(FloatPoint(-adjustedScrollOffset)); - } - - m_scrollingContentsLayer->setSize(scrollSize); - // FIXME: The paint offset and the scroll offset should really be separate concepts. - m_scrollingContentsLayer->setOffsetFromRenderer(scrollingContentsOffset, GraphicsLayer::DontSetNeedsDisplay); - - if (m_foregroundLayer) { - if (m_foregroundLayer->size() != m_scrollingContentsLayer->size()) - m_foregroundLayer->setSize(m_scrollingContentsLayer->size()); - m_foregroundLayer->setNeedsDisplay(); - m_foregroundLayer->setOffsetFromRenderer(m_scrollingContentsLayer->offsetFromRenderer()); - } - } - - if (m_squashingLayer) { - ASSERT(compositor()->layerSquashingEnabled()); - - IntRect totalSquashBounds; - for (size_t i = 0; i < m_squashedLayers.size(); ++i) { - IntRect squashedBounds = compositor()->calculateCompositedBounds(m_squashedLayers[i].renderLayer, m_squashedLayers[i].renderLayer); - - // Store the composited bounds before applying the offset. - // FIXME: consider whether it is more efficient or clarifies the math to store the compositedBounds after applying the offset. - m_squashedLayers[i].compositedBounds = squashedBounds; - - squashedBounds.move(m_squashedLayers[i].offsetFromBackingRoot); - totalSquashBounds.unite(squashedBounds); - } - - IntPoint squashLayerPosition; - // FIXME: this logic needs to update depending on what "containment" layers are added to CompositedLayerMapping due to other changes - if (m_ancestorClippingLayer) { - squashLayerPosition = IntPoint(m_ancestorClippingLayer->position().x() + totalSquashBounds.location().x(), - m_ancestorClippingLayer->position().y() + totalSquashBounds.location().y()); - } else { - squashLayerPosition = IntPoint(m_graphicsLayer->position().x() + totalSquashBounds.location().x(), - m_graphicsLayer->position().y() + totalSquashBounds.location().y()); - } - - m_squashingLayer->setPosition(squashLayerPosition); - m_squashingLayer->setSize(totalSquashBounds.size()); - - // Now that the position of the squashing layer is known, update the offsets for each squashed RenderLayer. - for (size_t i = 0; i < m_squashedLayers.size(); ++i) { - m_squashedLayers[i].offsetFromRenderer = IntSize(-m_squashedLayers[i].offsetFromBackingRoot.width() - m_graphicsLayer->position().x() + m_squashingLayer->position().x(), - -m_squashedLayers[i].offsetFromBackingRoot.height() - m_graphicsLayer->position().y() + m_squashingLayer->position().y()); - - // FIXME: find a better design to avoid this redundant value - most likely it will make - // sense to move the paint task info into RenderLayer's m_compositingProperties. - m_squashedLayers[i].renderLayer->setOffsetFromSquashingLayerOrigin(m_squashedLayers[i].offsetFromRenderer); - } - } - - if (m_owningLayer->scrollableArea()) - m_owningLayer->scrollableArea()->positionOverflowControls(); - - // We can't make this call in RenderLayerCompositor::allocateOrClearCompositedLayerMapping - // since it depends on whether compAncestor draws content, which gets updated later. - updateRequiresOwnBackingStoreForAncestorReasons(compAncestor); - - if (RuntimeEnabledFeatures::cssCompositingEnabled()) { - updateLayerBlendMode(style); - updateIsRootForIsolatedGroup(); - } - - updateContentsRect(isSimpleContainer); - updateBackgroundColor(isSimpleContainer); - updateDrawsContent(isSimpleContainer); - updateContentsOpaque(); - updateAfterWidgetResize(); - registerScrollingLayers(); - - updateCompositingReasons(); -} - -void CompositedLayerMapping::registerScrollingLayers() -{ - // Register fixed position layers and their containers with the scrolling coordinator. - ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer); - if (!scrollingCoordinator) - return; - - compositor()->updateViewportConstraintStatus(m_owningLayer); - - scrollingCoordinator->updateLayerPositionConstraint(m_owningLayer); - - // Page scale is applied as a transform on the root render view layer. Because the scroll - // layer is further up in the hierarchy, we need to avoid marking the root render view - // layer as a container. - bool isContainer = m_owningLayer->hasTransform() && !m_owningLayer->isRootLayer(); - // FIXME: we should make certain that childForSuperLayers will never be the m_squashingContainmentLayer here - scrollingCoordinator->setLayerIsContainerForFixedPositionLayers(childForSuperlayers(), isContainer); -} - -void CompositedLayerMapping::updateInternalHierarchy() -{ - // m_foregroundLayer has to be inserted in the correct order with child layers, - // so it's not inserted here. - if (m_ancestorClippingLayer) - m_ancestorClippingLayer->removeAllChildren(); - - m_graphicsLayer->removeFromParent(); - - if (m_ancestorClippingLayer) - m_ancestorClippingLayer->addChild(m_graphicsLayer.get()); - - if (m_childContainmentLayer) { - m_childContainmentLayer->removeFromParent(); - m_graphicsLayer->addChild(m_childContainmentLayer.get()); - } - - if (m_scrollingLayer) { - GraphicsLayer* superlayer = m_childContainmentLayer ? m_childContainmentLayer.get() : m_graphicsLayer.get(); - m_scrollingLayer->removeFromParent(); - superlayer->addChild(m_scrollingLayer.get()); - } - - // The clip for child layers does not include space for overflow controls, so they exist as - // siblings of the clipping layer if we have one. Normal children of this layer are set as - // children of the clipping layer. - if (m_layerForHorizontalScrollbar) { - m_layerForHorizontalScrollbar->removeFromParent(); - m_graphicsLayer->addChild(m_layerForHorizontalScrollbar.get()); - } - if (m_layerForVerticalScrollbar) { - m_layerForVerticalScrollbar->removeFromParent(); - m_graphicsLayer->addChild(m_layerForVerticalScrollbar.get()); - } - if (m_layerForScrollCorner) { - m_layerForScrollCorner->removeFromParent(); - m_graphicsLayer->addChild(m_layerForScrollCorner.get()); - } - - // The squashing containment layer, if it exists, becomes a no-op parent. - if (m_squashingLayer) { - ASSERT(compositor()->layerSquashingEnabled()); - ASSERT(m_squashingContainmentLayer); - - m_squashingContainmentLayer->removeAllChildren(); - - if (m_ancestorClippingLayer) - m_squashingContainmentLayer->addChild(m_ancestorClippingLayer.get()); - else - m_squashingContainmentLayer->addChild(m_graphicsLayer.get()); - - m_squashingContainmentLayer->addChild(m_squashingLayer.get()); - } -} - -void CompositedLayerMapping::updateContentsRect(bool isSimpleContainer) -{ - IntRect contentsRect; - if (isSimpleContainer && renderer()->hasBackground()) - contentsRect = backgroundBox(); - else - contentsRect = contentsBox(); - - m_graphicsLayer->setContentsRect(contentsRect); -} - -void CompositedLayerMapping::updateDrawsContent(bool isSimpleContainer) -{ - if (m_scrollingLayer) { - // We don't have to consider overflow controls, because we know that the scrollbars are drawn elsewhere. - // m_graphicsLayer only needs backing store if the non-scrolling parts (background, outlines, borders, shadows etc) need to paint. - // m_scrollingLayer never has backing store. - // m_scrollingContentsLayer only needs backing store if the scrolled contents need to paint. - bool hasNonScrollingPaintedContent = m_owningLayer->hasVisibleContent() && m_owningLayer->hasBoxDecorationsOrBackground(); - m_graphicsLayer->setDrawsContent(hasNonScrollingPaintedContent); - - bool hasScrollingPaintedContent = m_owningLayer->hasVisibleContent() && (renderer()->hasBackground() || paintsChildren()); - m_scrollingContentsLayer->setDrawsContent(hasScrollingPaintedContent); - return; - } - - bool hasPaintedContent = containsPaintedContent(isSimpleContainer); - if (hasPaintedContent && isAcceleratedCanvas(renderer())) { - CanvasRenderingContext* context = toHTMLCanvasElement(renderer()->node())->renderingContext(); - // Content layer may be null if context is lost. - if (blink::WebLayer* contentLayer = context->platformLayer()) { - Color bgColor; - if (contentLayerSupportsDirectBackgroundComposition(renderer())) { - bgColor = rendererBackgroundColor(); - hasPaintedContent = false; - } - contentLayer->setBackgroundColor(bgColor.rgb()); - } - } - - // FIXME: we could refine this to only allocate backings for one of these layers if possible. - m_graphicsLayer->setDrawsContent(hasPaintedContent); - if (m_foregroundLayer) - m_foregroundLayer->setDrawsContent(hasPaintedContent); - - if (m_backgroundLayer) - m_backgroundLayer->setDrawsContent(hasPaintedContent); -} - -// Return true if the layers changed. -bool CompositedLayerMapping::updateClippingLayers(bool needsAncestorClip, bool needsDescendantClip) -{ - bool layersChanged = false; - - if (needsAncestorClip) { - if (!m_ancestorClippingLayer) { - m_ancestorClippingLayer = createGraphicsLayer(CompositingReasonLayerForClip); - m_ancestorClippingLayer->setMasksToBounds(true); - layersChanged = true; - } - } else if (m_ancestorClippingLayer) { - m_ancestorClippingLayer->removeFromParent(); - m_ancestorClippingLayer = nullptr; - layersChanged = true; - } - - if (needsDescendantClip) { - // We don't need a child containment layer if we're the main frame render view - // layer. It's redundant as the frame clip above us will handle this clipping. - if (!m_childContainmentLayer && !m_isMainFrameRenderViewLayer) { - m_childContainmentLayer = createGraphicsLayer(CompositingReasonLayerForClip); - m_childContainmentLayer->setMasksToBounds(true); - layersChanged = true; - } - } else if (hasClippingLayer()) { - m_childContainmentLayer->removeFromParent(); - m_childContainmentLayer = nullptr; - layersChanged = true; - } - - return layersChanged; -} - -void CompositedLayerMapping::setBackgroundLayerPaintsFixedRootBackground(bool backgroundLayerPaintsFixedRootBackground) -{ - m_backgroundLayerPaintsFixedRootBackground = backgroundLayerPaintsFixedRootBackground; -} - -bool CompositedLayerMapping::updateOverflowControlsLayers(bool needsHorizontalScrollbarLayer, bool needsVerticalScrollbarLayer, bool needsScrollCornerLayer) -{ - bool horizontalScrollbarLayerChanged = false; - if (needsHorizontalScrollbarLayer) { - if (!m_layerForHorizontalScrollbar) { - m_layerForHorizontalScrollbar = createGraphicsLayer(CompositingReasonLayerForScrollbar); - horizontalScrollbarLayerChanged = true; - } - } else if (m_layerForHorizontalScrollbar) { - m_layerForHorizontalScrollbar = nullptr; - horizontalScrollbarLayerChanged = true; - } - - bool verticalScrollbarLayerChanged = false; - if (needsVerticalScrollbarLayer) { - if (!m_layerForVerticalScrollbar) { - m_layerForVerticalScrollbar = createGraphicsLayer(CompositingReasonLayerForScrollbar); - verticalScrollbarLayerChanged = true; - } - } else if (m_layerForVerticalScrollbar) { - m_layerForVerticalScrollbar = nullptr; - verticalScrollbarLayerChanged = true; - } - - bool scrollCornerLayerChanged = false; - if (needsScrollCornerLayer) { - if (!m_layerForScrollCorner) { - m_layerForScrollCorner = createGraphicsLayer(CompositingReasonLayerForScrollbar); - scrollCornerLayerChanged = true; - } - } else if (m_layerForScrollCorner) { - m_layerForScrollCorner = nullptr; - scrollCornerLayerChanged = true; - } - - if (ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer)) { - if (horizontalScrollbarLayerChanged) - scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_owningLayer->scrollableArea(), HorizontalScrollbar); - if (verticalScrollbarLayerChanged) - scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_owningLayer->scrollableArea(), VerticalScrollbar); - } - - return horizontalScrollbarLayerChanged || verticalScrollbarLayerChanged || scrollCornerLayerChanged; -} - -void CompositedLayerMapping::positionOverflowControlsLayers(const IntSize& offsetFromRoot) -{ - IntSize offsetFromRenderer = m_graphicsLayer->offsetFromRenderer(); - if (GraphicsLayer* layer = layerForHorizontalScrollbar()) { - Scrollbar* hBar = m_owningLayer->scrollableArea()->horizontalScrollbar(); - if (hBar) { - layer->setPosition(hBar->frameRect().location() - offsetFromRoot - offsetFromRenderer); - layer->setSize(hBar->frameRect().size()); - if (layer->hasContentsLayer()) - layer->setContentsRect(IntRect(IntPoint(), hBar->frameRect().size())); - } - layer->setDrawsContent(hBar && !layer->hasContentsLayer()); - } - - if (GraphicsLayer* layer = layerForVerticalScrollbar()) { - Scrollbar* vBar = m_owningLayer->scrollableArea()->verticalScrollbar(); - if (vBar) { - layer->setPosition(vBar->frameRect().location() - offsetFromRoot - offsetFromRenderer); - layer->setSize(vBar->frameRect().size()); - if (layer->hasContentsLayer()) - layer->setContentsRect(IntRect(IntPoint(), vBar->frameRect().size())); - } - layer->setDrawsContent(vBar && !layer->hasContentsLayer()); - } - - if (GraphicsLayer* layer = layerForScrollCorner()) { - const LayoutRect& scrollCornerAndResizer = m_owningLayer->scrollableArea()->scrollCornerAndResizerRect(); - layer->setPosition(scrollCornerAndResizer.location() - offsetFromRenderer); - layer->setSize(scrollCornerAndResizer.size()); - layer->setDrawsContent(!scrollCornerAndResizer.isEmpty()); - } -} - -bool CompositedLayerMapping::hasUnpositionedOverflowControlsLayers() const -{ - if (GraphicsLayer* layer = layerForHorizontalScrollbar()) { - if (!layer->drawsContent()) - return true; - } - - if (GraphicsLayer* layer = layerForVerticalScrollbar()) { - if (!layer->drawsContent()) - return true; - } - - if (GraphicsLayer* layer = layerForScrollCorner()) { - if (!layer->drawsContent()) - return true; - } - - return false; -} - -bool CompositedLayerMapping::updateForegroundLayer(bool needsForegroundLayer) -{ - bool layerChanged = false; - if (needsForegroundLayer) { - if (!m_foregroundLayer) { - m_foregroundLayer = createGraphicsLayer(CompositingReasonLayerForForeground); - m_foregroundLayer->setDrawsContent(true); - m_foregroundLayer->setPaintingPhase(GraphicsLayerPaintForeground); - layerChanged = true; - } - } else if (m_foregroundLayer) { - m_foregroundLayer->removeFromParent(); - m_foregroundLayer = nullptr; - layerChanged = true; - } - - if (layerChanged) - m_graphicsLayer->setPaintingPhase(paintingPhaseForPrimaryLayer()); - - return layerChanged; -} - -bool CompositedLayerMapping::updateBackgroundLayer(bool needsBackgroundLayer) -{ - bool layerChanged = false; - if (needsBackgroundLayer) { - if (!m_backgroundLayer) { - m_backgroundLayer = createGraphicsLayer(CompositingReasonLayerForBackground); - m_backgroundLayer->setDrawsContent(true); - m_backgroundLayer->setAnchorPoint(FloatPoint3D()); - m_backgroundLayer->setPaintingPhase(GraphicsLayerPaintBackground); -#if !OS(ANDROID) - m_backgroundLayer->contentLayer()->setDrawCheckerboardForMissingTiles(true); - m_graphicsLayer->contentLayer()->setDrawCheckerboardForMissingTiles(false); -#endif - layerChanged = true; - } - } else { - if (m_backgroundLayer) { - m_backgroundLayer->removeFromParent(); - m_backgroundLayer = nullptr; -#if !OS(ANDROID) - m_graphicsLayer->contentLayer()->setDrawCheckerboardForMissingTiles(true); -#endif - layerChanged = true; - } - } - - if (layerChanged && !m_owningLayer->renderer()->documentBeingDestroyed()) - compositor()->rootFixedBackgroundsChanged(); - - return layerChanged; -} - -bool CompositedLayerMapping::updateMaskLayer(bool needsMaskLayer) -{ - bool layerChanged = false; - if (needsMaskLayer) { - if (!m_maskLayer) { - m_maskLayer = createGraphicsLayer(CompositingReasonLayerForMask); - m_maskLayer->setDrawsContent(true); - m_maskLayer->setPaintingPhase(GraphicsLayerPaintMask); - layerChanged = true; - } - } else if (m_maskLayer) { - m_maskLayer = nullptr; - layerChanged = true; - } - - if (layerChanged) - m_graphicsLayer->setPaintingPhase(paintingPhaseForPrimaryLayer()); - - return layerChanged; -} - -bool CompositedLayerMapping::updateClippingMaskLayers(bool needsChildClippingMaskLayer) -{ - bool layerChanged = false; - if (needsChildClippingMaskLayer) { - if (!m_childClippingMaskLayer) { - m_childClippingMaskLayer = createGraphicsLayer(CompositingReasonLayerForMask); - m_childClippingMaskLayer->setDrawsContent(true); - m_childClippingMaskLayer->setPaintingPhase(GraphicsLayerPaintChildClippingMask); - layerChanged = true; - } - } else if (m_childClippingMaskLayer) { - m_childClippingMaskLayer = nullptr; - layerChanged = true; - } - return layerChanged; -} - -bool CompositedLayerMapping::updateScrollingLayers(bool needsScrollingLayers) -{ - ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer); - - bool layerChanged = false; - if (needsScrollingLayers) { - if (!m_scrollingLayer) { - // Outer layer which corresponds with the scroll view. - m_scrollingLayer = createGraphicsLayer(CompositingReasonLayerForClip); - m_scrollingLayer->setDrawsContent(false); - m_scrollingLayer->setMasksToBounds(true); - - // Inner layer which renders the content that scrolls. - m_scrollingContentsLayer = createGraphicsLayer(CompositingReasonLayerForScrollingContainer); - m_scrollingContentsLayer->setDrawsContent(true); - GraphicsLayerPaintingPhase paintPhase = GraphicsLayerPaintOverflowContents | GraphicsLayerPaintCompositedScroll; - if (!m_foregroundLayer) - paintPhase |= GraphicsLayerPaintForeground; - m_scrollingContentsLayer->setPaintingPhase(paintPhase); - m_scrollingLayer->addChild(m_scrollingContentsLayer.get()); - - layerChanged = true; - if (scrollingCoordinator) - scrollingCoordinator->scrollableAreaScrollLayerDidChange(m_owningLayer->scrollableArea()); - } - } else if (m_scrollingLayer) { - m_scrollingLayer = nullptr; - m_scrollingContentsLayer = nullptr; - layerChanged = true; - if (scrollingCoordinator) - scrollingCoordinator->scrollableAreaScrollLayerDidChange(m_owningLayer->scrollableArea()); - } - - if (layerChanged) { - updateInternalHierarchy(); - m_graphicsLayer->setPaintingPhase(paintingPhaseForPrimaryLayer()); - m_graphicsLayer->setNeedsDisplay(); - if (renderer()->view()) - compositor()->scrollingLayerDidChange(m_owningLayer); - } - - return layerChanged; -} - -static void updateScrollParentForGraphicsLayer(GraphicsLayer* layer, GraphicsLayer* topmostLayer, RenderLayer* scrollParent, ScrollingCoordinator* scrollingCoordinator) -{ - if (!layer) - return; - - // Only the topmost layer has a scroll parent. All other layers have a null scroll parent. - if (layer != topmostLayer) - scrollParent = 0; - - scrollingCoordinator->updateScrollParentForGraphicsLayer(layer, scrollParent); -} - -void CompositedLayerMapping::updateScrollParent(RenderLayer* scrollParent) -{ - - if (ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer)) { - GraphicsLayer* topmostLayer = childForSuperlayers(); - updateScrollParentForGraphicsLayer(m_squashingContainmentLayer.get(), topmostLayer, scrollParent, scrollingCoordinator); - updateScrollParentForGraphicsLayer(m_ancestorClippingLayer.get(), topmostLayer, scrollParent, scrollingCoordinator); - updateScrollParentForGraphicsLayer(m_graphicsLayer.get(), topmostLayer, scrollParent, scrollingCoordinator); - } -} - -void CompositedLayerMapping::updateClipParent(RenderLayer* clipParent) -{ - if (ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer)) - scrollingCoordinator->updateClipParentForGraphicsLayer(m_graphicsLayer.get(), clipParent); -} - -bool CompositedLayerMapping::updateSquashingLayers(bool needsSquashingLayers) -{ - bool layersChanged = false; - - if (needsSquashingLayers) { - ASSERT(compositor()->layerSquashingEnabled()); - - if (!m_squashingLayer) { - ASSERT(!m_squashingContainmentLayer); - - m_squashingLayer = createGraphicsLayer(CompositingReasonOverlap); - m_squashingLayer->setDrawsContent(true); - m_squashingLayer->setNeedsDisplay(); - layersChanged = true; - - // FIXME: containment layer needs a new CompositingReason, CompositingReasonOverlap is not appropriate. - m_squashingContainmentLayer = createGraphicsLayer(CompositingReasonOverlap); - // FIXME: reflections should force transform-style to be flat in the style: https://bugs.webkit.org/show_bug.cgi?id=106959 - bool preserves3D = renderer()->style()->transformStyle3D() == TransformStyle3DPreserve3D && !renderer()->hasReflection(); - m_squashingContainmentLayer->setPreserves3D(preserves3D); - layersChanged = true; - } - - ASSERT(m_squashingLayer && m_squashingContainmentLayer); - } else { - if (m_squashingLayer) { - m_squashingLayer->removeFromParent(); - m_squashingLayer = nullptr; - layersChanged = true; - // FIXME: do we need to invalidate something here? - - ASSERT(m_squashingContainmentLayer); - m_squashingContainmentLayer->removeFromParent(); - m_squashingContainmentLayer = nullptr; - layersChanged = true; - } - - ASSERT(!m_squashingLayer && !m_squashingContainmentLayer); - } - - return layersChanged; -} - -GraphicsLayerPaintingPhase CompositedLayerMapping::paintingPhaseForPrimaryLayer() const -{ - unsigned phase = 0; - if (!m_backgroundLayer) - phase |= GraphicsLayerPaintBackground; - if (!m_foregroundLayer) - phase |= GraphicsLayerPaintForeground; - if (!m_maskLayer) - phase |= GraphicsLayerPaintMask; - - if (m_scrollingContentsLayer) { - phase &= ~GraphicsLayerPaintForeground; - phase |= GraphicsLayerPaintCompositedScroll; - } - - if (m_owningLayer->compositingReasons() & CompositingReasonOverflowScrollingParent) - phase |= GraphicsLayerPaintCompositedScroll; - - return static_cast<GraphicsLayerPaintingPhase>(phase); -} - -float CompositedLayerMapping::compositingOpacity(float rendererOpacity) const -{ - float finalOpacity = rendererOpacity; - - for (RenderLayer* curr = m_owningLayer->parent(); curr; curr = curr->parent()) { - // We only care about parents that are stacking contexts. - // Recall that opacity creates stacking context. - if (!curr->stackingNode()->isStackingContainer()) - continue; - - // If we found a composited layer, regardless of whether it actually - // paints into it, we want to compute opacity relative to it. So we can - // break here. - // - // FIXME: with grouped backings, a composited descendant will have to - // continue past the grouped (squashed) layers that its parents may - // contribute to. This whole confusion can be avoided by specifying - // explicitly the composited ancestor where we would stop accumulating - // opacity. - if (curr->compositingState() == PaintsIntoOwnBacking || curr->compositingState() == HasOwnBackingButPaintsIntoAncestor) - break; - - finalOpacity *= curr->renderer()->opacity(); - } - - return finalOpacity; -} - -Color CompositedLayerMapping::rendererBackgroundColor() const -{ - RenderObject* backgroundRenderer = renderer(); - if (backgroundRenderer->isRoot()) - backgroundRenderer = backgroundRenderer->rendererForRootBackground(); - - return backgroundRenderer->resolveColor(CSSPropertyBackgroundColor); -} - -void CompositedLayerMapping::updateBackgroundColor(bool isSimpleContainer) -{ - Color backgroundColor = rendererBackgroundColor(); - if (isSimpleContainer) { - m_graphicsLayer->setContentsToSolidColor(backgroundColor); - m_graphicsLayer->setBackgroundColor(Color()); - } else { - // An unset (invalid) color will remove the solid color. - m_graphicsLayer->setContentsToSolidColor(Color()); - m_graphicsLayer->setBackgroundColor(backgroundColor); - } -} - -static bool supportsDirectBoxDecorationsComposition(const RenderObject* renderer) -{ - if (renderer->hasClip()) - return false; - - if (hasBoxDecorationsOrBackgroundImage(renderer->style())) - return false; - - // FIXME: we should be able to allow backgroundComposite; However since this is not a common use case it has been deferred for now. - if (renderer->style()->backgroundComposite() != CompositeSourceOver) - return false; - - if (renderer->style()->backgroundClip() == TextFillBox) - return false; - - return true; -} - -bool CompositedLayerMapping::paintsBoxDecorations() const -{ - if (!m_owningLayer->hasVisibleBoxDecorations()) - return false; - - if (!supportsDirectBoxDecorationsComposition(renderer())) - return true; - - return false; -} - -bool CompositedLayerMapping::paintsChildren() const -{ - if (m_owningLayer->hasVisibleContent() && m_owningLayer->hasNonEmptyChildRenderers()) - return true; - - if (hasVisibleNonCompositingDescendantLayers()) - return true; - - return false; -} - -static bool isCompositedPlugin(RenderObject* renderer) -{ - return renderer->isEmbeddedObject() && toRenderEmbeddedObject(renderer)->allowsAcceleratedCompositing(); -} - -// 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. -bool CompositedLayerMapping::isSimpleContainerCompositingLayer() const -{ - RenderObject* renderObject = renderer(); - if (renderObject->hasMask()) // masks require special treatment - return false; - - if (renderObject->isReplaced() && !isCompositedPlugin(renderObject)) - return false; - - if (paintsBoxDecorations() || paintsChildren()) - return false; - - if (renderObject->isRenderRegion()) - return false; - - if (renderObject->node() && renderObject->node()->isDocumentNode()) { - // Look to see if the root object has a non-simple background - RenderObject* rootObject = renderObject->document().documentElement() ? renderObject->document().documentElement()->renderer() : 0; - if (!rootObject) - return false; - - 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). - if (hasBoxDecorationsOrBackgroundImage(style)) - return false; - - // Now look at the body's renderer. - HTMLElement* body = renderObject->document().body(); - RenderObject* bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0; - if (!bodyObject) - return false; - - style = bodyObject->style(); - - if (hasBoxDecorationsOrBackgroundImage(style)) - return false; - } - - return true; -} - -static bool hasVisibleNonCompositingDescendant(RenderLayer* parent) -{ - // FIXME: We shouldn't be called with a stale z-order lists. See bug 85512. - parent->stackingNode()->updateLayerListsIfNeeded(); - -#if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(parent->stackingNode()); -#endif - - RenderLayerStackingNodeIterator normalFlowIterator(*parent->stackingNode(), NormalFlowChildren); - while (RenderLayerStackingNode* curNode = normalFlowIterator.next()) { - RenderLayer* curLayer = curNode->layer(); - if (!curLayer->hasCompositedLayerMapping() - && (curLayer->hasVisibleContent() || hasVisibleNonCompositingDescendant(curLayer))) - return true; - } - - if (!parent->hasVisibleDescendant()) - return false; - - RenderLayerStackingNodeIterator zOrderIterator(*parent->stackingNode(), NegativeZOrderChildren | PositiveZOrderChildren); - while (RenderLayerStackingNode* curNode = zOrderIterator.next()) { - RenderLayer* curLayer = curNode->layer(); - if (!curLayer->hasCompositedLayerMapping() - && (curLayer->hasVisibleContent() || hasVisibleNonCompositingDescendant(curLayer))) - return true; - } - - return false; -} - -// FIXME: By name the implementation is correct. But the code that uses this function means something -// very slightly different - the implementation needs to also include composited descendants that -// don't paint into their own backing, and instead paint into this backing. -bool CompositedLayerMapping::hasVisibleNonCompositingDescendantLayers() const -{ - return hasVisibleNonCompositingDescendant(m_owningLayer); -} - -bool CompositedLayerMapping::containsPaintedContent(bool isSimpleContainer) const -{ - if (isSimpleContainer || paintsIntoCompositedAncestor() || m_artificiallyInflatedBounds || m_owningLayer->isReflection()) - return false; - - if (isDirectlyCompositedImage()) - return false; - - // FIXME: we could optimize cases where the image, video or canvas is known to fill the border box entirely, - // and set background color on the layer in that case, instead of allocating backing store and painting. - if (renderer()->isVideo() && toRenderVideo(renderer())->shouldDisplayVideo()) - return m_owningLayer->hasBoxDecorationsOrBackground(); - - return true; -} - -// An image can be directly compositing if it's the sole content of the layer, and has no box decorations -// that require painting. Direct compositing saves backing store. -bool CompositedLayerMapping::isDirectlyCompositedImage() const -{ - RenderObject* renderObject = renderer(); - - if (!renderObject->isImage() || m_owningLayer->hasBoxDecorationsOrBackground() || renderObject->hasClip()) - return false; - - RenderImage* imageRenderer = toRenderImage(renderObject); - if (ImageResource* cachedImage = imageRenderer->cachedImage()) { - if (!cachedImage->hasImage()) - return false; - - Image* image = cachedImage->imageForRenderer(imageRenderer); - return image->isBitmapImage(); - } - - return false; -} - -void CompositedLayerMapping::contentChanged(ContentChangeType changeType) -{ - if ((changeType == ImageChanged) && isDirectlyCompositedImage()) { - updateImageContents(); - return; - } - - if ((changeType == MaskImageChanged) && m_maskLayer) { - // The composited layer bounds relies on box->maskClipRect(), which changes - // when the mask image becomes available. - updateAfterLayout(CompositingChildrenOnly | IsUpdateRoot); - } - - if ((changeType == CanvasChanged || changeType == CanvasPixelsChanged) && isAcceleratedCanvas(renderer())) { - m_graphicsLayer->setContentsNeedsDisplay(); - return; - } -} - -void CompositedLayerMapping::updateImageContents() -{ - ASSERT(renderer()->isImage()); - RenderImage* imageRenderer = toRenderImage(renderer()); - - ImageResource* cachedImage = imageRenderer->cachedImage(); - if (!cachedImage) - return; - - Image* image = cachedImage->imageForRenderer(imageRenderer); - if (!image) - return; - - // We have to wait until the image is fully loaded before setting it on the layer. - if (!cachedImage->isLoaded()) - return; - - // This is a no-op if the layer doesn't have an inner layer for the image. - m_graphicsLayer->setContentsToImage(image); - bool isSimpleContainer = false; - updateDrawsContent(isSimpleContainer); - - // Image animation is "lazy", in that it automatically stops unless someone is drawing - // the image. So we have to kick the animation each time; this has the downside that the - // image will keep animating, even if its layer is not visible. - image->startAnimation(); -} - -FloatPoint3D CompositedLayerMapping::computeTransformOrigin(const IntRect& borderBox) const -{ - RenderStyle* style = renderer()->style(); - - FloatPoint3D origin; - origin.setX(floatValueForLength(style->transformOriginX(), borderBox.width())); - origin.setY(floatValueForLength(style->transformOriginY(), borderBox.height())); - origin.setZ(style->transformOriginZ()); - - return origin; -} - -FloatPoint CompositedLayerMapping::computePerspectiveOrigin(const IntRect& borderBox) const -{ - RenderStyle* style = renderer()->style(); - - float boxWidth = borderBox.width(); - float boxHeight = borderBox.height(); - - FloatPoint origin; - origin.setX(floatValueForLength(style->perspectiveOriginX(), boxWidth)); - origin.setY(floatValueForLength(style->perspectiveOriginY(), boxHeight)); - - return origin; -} - -// Return the offset from the top-left of this compositing layer at which the renderer's contents are painted. -IntSize CompositedLayerMapping::contentOffsetInCompostingLayer() const -{ - return IntSize(-m_compositedBounds.x(), -m_compositedBounds.y()); -} - -IntRect CompositedLayerMapping::contentsBox() const -{ - IntRect contentsBox = contentsRect(renderer()); - contentsBox.move(contentOffsetInCompostingLayer()); - return contentsBox; -} - -IntRect CompositedLayerMapping::backgroundBox() const -{ - IntRect backgroundBox = backgroundRect(renderer()); - backgroundBox.move(contentOffsetInCompostingLayer()); - return backgroundBox; -} - -GraphicsLayer* CompositedLayerMapping::parentForSublayers() const -{ - if (m_scrollingContentsLayer) - return m_scrollingContentsLayer.get(); - - return m_childContainmentLayer ? m_childContainmentLayer.get() : m_graphicsLayer.get(); -} - -GraphicsLayer* CompositedLayerMapping::childForSuperlayers() const -{ - if (m_squashingContainmentLayer) - return m_squashingContainmentLayer.get(); - - if (m_ancestorClippingLayer) - return m_ancestorClippingLayer.get(); - - return m_graphicsLayer.get(); -} - -bool CompositedLayerMapping::updateRequiresOwnBackingStoreForAncestorReasons(const RenderLayer* compositingAncestorLayer) -{ - bool previousRequiresOwnBackingStoreForAncestorReasons = m_requiresOwnBackingStoreForAncestorReasons; - bool previousPaintsIntoCompositedAncestor = paintsIntoCompositedAncestor(); - bool canPaintIntoAncestor = compositingAncestorLayer - && (compositingAncestorLayer->compositedLayerMapping()->mainGraphicsLayer()->drawsContent() - || compositingAncestorLayer->compositedLayerMapping()->paintsIntoCompositedAncestor()); - m_requiresOwnBackingStoreForAncestorReasons = !canPaintIntoAncestor; - - if (paintsIntoCompositedAncestor() != previousPaintsIntoCompositedAncestor) - paintsIntoCompositedAncestorChanged(); - return m_requiresOwnBackingStoreForAncestorReasons != previousRequiresOwnBackingStoreForAncestorReasons; -} - -bool CompositedLayerMapping::updateRequiresOwnBackingStoreForIntrinsicReasons() -{ - bool previousRequiresOwnBackingStoreForIntrinsicReasons = m_requiresOwnBackingStoreForIntrinsicReasons; - bool previousPaintsIntoCompositedAncestor = paintsIntoCompositedAncestor(); - RenderObject* renderer = m_owningLayer->renderer(); - m_requiresOwnBackingStoreForIntrinsicReasons = m_owningLayer->isRootLayer() - || (m_owningLayer->compositingReasons() & CompositingReasonComboReasonsThatRequireOwnBacking) - || m_owningLayer->transform() - || m_owningLayer->clipsCompositingDescendantsWithBorderRadius() // FIXME: Revisit this if the paintsIntoCompositedAncestor state is removed. - || renderer->isTransparent() - || renderer->hasMask() - || renderer->hasReflection() - || renderer->hasFilter(); - - if (paintsIntoCompositedAncestor() != previousPaintsIntoCompositedAncestor) - paintsIntoCompositedAncestorChanged(); - return m_requiresOwnBackingStoreForIntrinsicReasons != previousRequiresOwnBackingStoreForIntrinsicReasons; -} - -void CompositedLayerMapping::paintsIntoCompositedAncestorChanged() -{ - // The answer to paintsIntoCompositedAncestor() affects cached clip rects, so when - // it changes we have to clear clip rects on descendants. - m_owningLayer->clipper().clearClipRectsIncludingDescendants(PaintingClipRects); - m_owningLayer->repainter().computeRepaintRectsIncludingDescendants(); - - compositor()->repaintInCompositedAncestor(m_owningLayer, compositedBounds()); -} - -void CompositedLayerMapping::setBlendMode(blink::WebBlendMode blendMode) -{ - if (m_ancestorClippingLayer) { - m_ancestorClippingLayer->setBlendMode(blendMode); - m_graphicsLayer->setBlendMode(blink::WebBlendModeNormal); - } else { - m_graphicsLayer->setBlendMode(blendMode); - } -} - -void CompositedLayerMapping::setContentsNeedDisplay() -{ - ASSERT(!paintsIntoCompositedAncestor()); - - if (m_graphicsLayer && m_graphicsLayer->drawsContent()) - m_graphicsLayer->setNeedsDisplay(); - - if (m_foregroundLayer && m_foregroundLayer->drawsContent()) - m_foregroundLayer->setNeedsDisplay(); - - if (m_backgroundLayer && m_backgroundLayer->drawsContent()) - m_backgroundLayer->setNeedsDisplay(); - - if (m_maskLayer && m_maskLayer->drawsContent()) - m_maskLayer->setNeedsDisplay(); - - if (m_childClippingMaskLayer && m_childClippingMaskLayer->drawsContent()) - m_childClippingMaskLayer->setNeedsDisplay(); - - if (m_scrollingContentsLayer && m_scrollingContentsLayer->drawsContent()) - m_scrollingContentsLayer->setNeedsDisplay(); -} - -// r is in the coordinate space of the layer's render object -void CompositedLayerMapping::setContentsNeedDisplayInRect(const IntRect& r) -{ - ASSERT(!paintsIntoCompositedAncestor()); - - if (m_graphicsLayer && m_graphicsLayer->drawsContent()) { - IntRect layerDirtyRect = r; - layerDirtyRect.move(-m_graphicsLayer->offsetFromRenderer()); - m_graphicsLayer->setNeedsDisplayInRect(layerDirtyRect); - } - - if (m_foregroundLayer && m_foregroundLayer->drawsContent()) { - IntRect layerDirtyRect = r; - layerDirtyRect.move(-m_foregroundLayer->offsetFromRenderer()); - m_foregroundLayer->setNeedsDisplayInRect(layerDirtyRect); - } - - // FIXME: need to split out repaints for the background. - if (m_backgroundLayer && m_backgroundLayer->drawsContent()) { - IntRect layerDirtyRect = r; - layerDirtyRect.move(-m_backgroundLayer->offsetFromRenderer()); - m_backgroundLayer->setNeedsDisplayInRect(layerDirtyRect); - } - - if (m_maskLayer && m_maskLayer->drawsContent()) { - IntRect layerDirtyRect = r; - layerDirtyRect.move(-m_maskLayer->offsetFromRenderer()); - m_maskLayer->setNeedsDisplayInRect(layerDirtyRect); - } - - if (m_childClippingMaskLayer && m_childClippingMaskLayer->drawsContent()) { - IntRect layerDirtyRect = r; - layerDirtyRect.move(-m_childClippingMaskLayer->offsetFromRenderer()); - m_childClippingMaskLayer->setNeedsDisplayInRect(layerDirtyRect); - } - - if (m_scrollingContentsLayer && m_scrollingContentsLayer->drawsContent()) { - IntRect layerDirtyRect = r; - layerDirtyRect.move(-m_scrollingContentsLayer->offsetFromRenderer()); - m_scrollingContentsLayer->setNeedsDisplayInRect(layerDirtyRect); - } -} - -void CompositedLayerMapping::doPaintTask(GraphicsLayerPaintInfo& paintInfo, GraphicsContext* context, - const IntRect& clip) // In the coords of rootLayer. -{ - if (paintsIntoCompositedAncestor()) { - ASSERT_NOT_REACHED(); - return; - } - - FontCachePurgePreventer fontCachePurgePreventer; - - PaintLayerFlags paintFlags = 0; - if (paintInfo.paintingPhase & GraphicsLayerPaintBackground) - paintFlags |= PaintLayerPaintingCompositingBackgroundPhase; - if (paintInfo.paintingPhase & GraphicsLayerPaintForeground) - paintFlags |= PaintLayerPaintingCompositingForegroundPhase; - if (paintInfo.paintingPhase & GraphicsLayerPaintMask) - paintFlags |= PaintLayerPaintingCompositingMaskPhase; - if (paintInfo.paintingPhase & GraphicsLayerPaintChildClippingMask) - paintFlags |= PaintLayerPaintingChildClippingMaskPhase; - if (paintInfo.paintingPhase & GraphicsLayerPaintOverflowContents) - paintFlags |= PaintLayerPaintingOverflowContents; - if (paintInfo.paintingPhase & GraphicsLayerPaintCompositedScroll) - paintFlags |= PaintLayerPaintingCompositingScrollingPhase; - - if (paintInfo.isBackgroundLayer) - paintFlags |= (PaintLayerPaintingRootBackgroundOnly | PaintLayerPaintingCompositingForegroundPhase); // Need PaintLayerPaintingCompositingForegroundPhase to walk child layers. - else if (compositor()->fixedRootBackgroundLayer()) - paintFlags |= PaintLayerPaintingSkipRootBackground; - - // Note carefully: in theory it is appropriate to invoke context->save() here - // and restore the context after painting. For efficiency, we are assuming that - // it is equivalent to manually undo this offset translation, which means we are - // assuming that the context's space was not affected by the RenderLayer - // painting code. - - LayoutSize offset = paintInfo.offsetFromRenderer; - context->translate(-offset); - LayoutRect relativeClip(clip); - relativeClip.move(offset); - - // The dirtyRect is in the coords of the painting root. - IntRect dirtyRect = pixelSnappedIntRect(relativeClip); - if (!(paintInfo.paintingPhase & GraphicsLayerPaintOverflowContents)) - dirtyRect.intersect(paintInfo.compositedBounds); - -#ifndef NDEBUG - paintInfo.renderLayer->renderer()->assertSubtreeIsLaidOut(); -#endif - - if (paintInfo.renderLayer->compositingState() != PaintsIntoGroupedBacking) { - // FIXME: GraphicsLayers need a way to split for RenderRegions. - LayerPaintingInfo paintingInfo(paintInfo.renderLayer, dirtyRect, PaintBehaviorNormal, LayoutSize()); - paintInfo.renderLayer->paintLayerContents(context, paintingInfo, paintFlags); - - ASSERT(!paintInfo.isBackgroundLayer || paintFlags & PaintLayerPaintingRootBackgroundOnly); - - if (paintInfo.renderLayer->containsDirtyOverlayScrollbars()) - paintInfo.renderLayer->paintLayerContents(context, paintingInfo, paintFlags | PaintLayerPaintingOverlayScrollbars); - } else { - ASSERT(compositor()->layerSquashingEnabled()); - LayerPaintingInfo paintingInfo(paintInfo.renderLayer, dirtyRect, PaintBehaviorNormal, LayoutSize()); - paintInfo.renderLayer->paintLayer(context, paintingInfo, paintFlags); - } - - ASSERT(!paintInfo.renderLayer->m_usedTransparency); - - // Manually restore the context to its original state by applying the opposite translation. - context->translate(offset); -} - -static void paintScrollbar(Scrollbar* scrollbar, GraphicsContext& context, const IntRect& clip) -{ - if (!scrollbar) - return; - - context.save(); - const IntRect& scrollbarRect = scrollbar->frameRect(); - context.translate(-scrollbarRect.x(), -scrollbarRect.y()); - IntRect transformedClip = clip; - transformedClip.moveBy(scrollbarRect.location()); - scrollbar->paint(&context, transformedClip); - context.restore(); -} - -// Up-call from compositing layer drawing callback. -void CompositedLayerMapping::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& context, GraphicsLayerPaintingPhase paintingPhase, const IntRect& clip) -{ -#ifndef NDEBUG - if (Page* page = renderer()->frame()->page()) - page->setIsPainting(true); -#endif - InspectorInstrumentation::willPaint(m_owningLayer->renderer(), graphicsLayer); - - if (graphicsLayer == m_graphicsLayer.get() - || graphicsLayer == m_foregroundLayer.get() - || graphicsLayer == m_backgroundLayer.get() - || graphicsLayer == m_maskLayer.get() - || graphicsLayer == m_childClippingMaskLayer.get() - || graphicsLayer == m_scrollingContentsLayer.get()) { - - GraphicsLayerPaintInfo paintInfo; - paintInfo.renderLayer = m_owningLayer; - paintInfo.compositedBounds = compositedBounds(); - paintInfo.offsetFromRenderer = graphicsLayer->offsetFromRenderer(); - paintInfo.paintingPhase = paintingPhase; - paintInfo.isBackgroundLayer = (graphicsLayer == m_backgroundLayer); - - // We have to use the same root as for hit testing, because both methods can compute and cache clipRects. - doPaintTask(paintInfo, &context, clip); - } else if (graphicsLayer == m_squashingLayer.get()) { - ASSERT(compositor()->layerSquashingEnabled()); - for (size_t i = 0; i < m_squashedLayers.size(); ++i) - doPaintTask(m_squashedLayers[i], &context, clip); - } else if (graphicsLayer == layerForHorizontalScrollbar()) { - paintScrollbar(m_owningLayer->scrollableArea()->horizontalScrollbar(), context, clip); - } else if (graphicsLayer == layerForVerticalScrollbar()) { - paintScrollbar(m_owningLayer->scrollableArea()->verticalScrollbar(), context, clip); - } else if (graphicsLayer == layerForScrollCorner()) { - const IntRect& scrollCornerAndResizer = m_owningLayer->scrollableArea()->scrollCornerAndResizerRect(); - context.save(); - context.translate(-scrollCornerAndResizer.x(), -scrollCornerAndResizer.y()); - IntRect transformedClip = clip; - transformedClip.moveBy(scrollCornerAndResizer.location()); - m_owningLayer->scrollableArea()->paintScrollCorner(&context, IntPoint(), transformedClip); - m_owningLayer->scrollableArea()->paintResizer(&context, IntPoint(), transformedClip); - context.restore(); - } - InspectorInstrumentation::didPaint(m_owningLayer->renderer(), graphicsLayer, &context, clip); -#ifndef NDEBUG - if (Page* page = renderer()->frame()->page()) - page->setIsPainting(false); -#endif -} - -void CompositedLayerMapping::didCommitChangesForLayer(const GraphicsLayer* layer) const -{ -} - -bool CompositedLayerMapping::getCurrentTransform(const GraphicsLayer* graphicsLayer, TransformationMatrix& transform) const -{ - if (graphicsLayer != m_graphicsLayer.get()) - return false; - - if (m_owningLayer->hasTransform()) { - transform = m_owningLayer->currentTransform(RenderStyle::ExcludeTransformOrigin); - return true; - } - return false; -} - -bool CompositedLayerMapping::isTrackingRepaints() const -{ - GraphicsLayerClient* client = compositor(); - return client ? client->isTrackingRepaints() : false; -} - -static void collectTrackedRepaintRectsForGraphicsLayer(GraphicsLayer* graphicsLayer, Vector<FloatRect>& rects) -{ - if (graphicsLayer) - graphicsLayer->collectTrackedRepaintRects(rects); -} - -PassOwnPtr<Vector<FloatRect> > CompositedLayerMapping::collectTrackedRepaintRects() const -{ - OwnPtr<Vector<FloatRect> > rects = adoptPtr(new Vector<FloatRect>); - collectTrackedRepaintRectsForGraphicsLayer(m_ancestorClippingLayer.get(), *rects); - collectTrackedRepaintRectsForGraphicsLayer(m_graphicsLayer.get(), *rects); - collectTrackedRepaintRectsForGraphicsLayer(m_childContainmentLayer.get(), *rects); - collectTrackedRepaintRectsForGraphicsLayer(m_scrollingLayer.get(), *rects); - collectTrackedRepaintRectsForGraphicsLayer(m_scrollingContentsLayer.get(), *rects); - collectTrackedRepaintRectsForGraphicsLayer(m_maskLayer.get(), *rects); - collectTrackedRepaintRectsForGraphicsLayer(m_childClippingMaskLayer.get(), *rects); - collectTrackedRepaintRectsForGraphicsLayer(m_foregroundLayer.get(), *rects); - collectTrackedRepaintRectsForGraphicsLayer(m_backgroundLayer.get(), *rects); - collectTrackedRepaintRectsForGraphicsLayer(m_layerForHorizontalScrollbar.get(), *rects); - collectTrackedRepaintRectsForGraphicsLayer(m_layerForVerticalScrollbar.get(), *rects); - collectTrackedRepaintRectsForGraphicsLayer(m_layerForScrollCorner.get(), *rects); - return rects.release(); -} - -#ifndef NDEBUG -void CompositedLayerMapping::verifyNotPainting() -{ - ASSERT(!renderer()->frame()->page() || !renderer()->frame()->page()->isPainting()); -} -#endif - -bool CompositedLayerMapping::startAnimation(double timeOffset, const CSSAnimationData* anim, const KeyframeList& keyframes) -{ - bool hasTransform = renderer()->isBox() && keyframes.containsProperty(CSSPropertyWebkitTransform); - IntSize boxSize; - if (hasTransform) - boxSize = toRenderBox(renderer())->pixelSnappedBorderBoxRect().size(); - WebAnimations animations(m_animationProvider->startAnimation(timeOffset, anim, keyframes, hasTransform, boxSize)); - if (animations.isEmpty()) - return false; - - bool hasOpacity = keyframes.containsProperty(CSSPropertyOpacity); - bool hasFilter = keyframes.containsProperty(CSSPropertyWebkitFilter); - int animationId = m_animationProvider->getWebAnimationId(keyframes.animationName()); - - // Animating only some properties of the animation is not supported. So if the - // GraphicsLayer rejects any property of the animation, we have to remove the - // animation and return false to indicate un-accelerated animation is required. - if (hasTransform) { - if (!animations.m_transformAnimation || !m_graphicsLayer->addAnimation(animations.m_transformAnimation.release())) - return false; - } - if (hasOpacity) { - if (!animations.m_opacityAnimation || !m_graphicsLayer->addAnimation(animations.m_opacityAnimation.release())) { - if (hasTransform) - m_graphicsLayer->removeAnimation(animationId); - return false; - } - } - if (hasFilter) { - if (!animations.m_filterAnimation || !m_graphicsLayer->addAnimation(animations.m_filterAnimation.release())) { - if (hasTransform || hasOpacity) - m_graphicsLayer->removeAnimation(animationId); - return false; - } - } - return true; -} - -void CompositedLayerMapping::animationPaused(double timeOffset, const String& animationName) -{ - int animationId = m_animationProvider->getWebAnimationId(animationName); - ASSERT(animationId); - m_graphicsLayer->pauseAnimation(animationId, timeOffset); -} - -void CompositedLayerMapping::animationFinished(const String& animationName) -{ - int animationId = m_animationProvider->getWebAnimationId(animationName); - ASSERT(animationId); - m_graphicsLayer->removeAnimation(animationId); -} - -bool CompositedLayerMapping::startTransition(double timeOffset, CSSPropertyID property, const RenderStyle* fromStyle, const RenderStyle* toStyle) -{ - ASSERT(property != CSSPropertyInvalid); - IntSize boxSize; - if (property == CSSPropertyWebkitTransform && m_owningLayer->hasTransform()) { - ASSERT(renderer()->isBox()); - boxSize = toRenderBox(renderer())->pixelSnappedBorderBoxRect().size(); - } - float fromOpacity = 0; - float toOpacity = 0; - if (property == CSSPropertyOpacity) { - fromOpacity = compositingOpacity(fromStyle->opacity()); - toOpacity = compositingOpacity(toStyle->opacity()); - } - - // Although KeyframeAnimation can have multiple properties of the animation, ImplicitAnimation (= Transition) has only one animation property. - WebAnimations animations(m_animationProvider->startTransition(timeOffset, property, fromStyle, - toStyle, m_owningLayer->hasTransform(), m_owningLayer->hasFilter(), boxSize, fromOpacity, toOpacity)); - if (animations.m_transformAnimation && m_graphicsLayer->addAnimation(animations.m_transformAnimation.release())) { - // To ensure that the correct transform is visible when the animation ends, also set the final transform. - updateTransform(toStyle); - return true; - } - if (animations.m_opacityAnimation && m_graphicsLayer->addAnimation(animations.m_opacityAnimation.release())) { - // To ensure that the correct opacity is visible when the animation ends, also set the final opacity. - updateOpacity(toStyle); - return true; - } - if (animations.m_filterAnimation && m_graphicsLayer->addAnimation(animations.m_filterAnimation.release())) { - // To ensure that the correct filter is visible when the animation ends, also set the final filter. - updateFilters(toStyle); - return true; - } - - return false; -} - -void CompositedLayerMapping::transitionPaused(double timeOffset, CSSPropertyID property) -{ - int animationId = m_animationProvider->getWebAnimationId(property); - ASSERT(animationId); - m_graphicsLayer->pauseAnimation(animationId, timeOffset); -} - -void CompositedLayerMapping::transitionFinished(CSSPropertyID property) -{ - int animationId = m_animationProvider->getWebAnimationId(property); - ASSERT(animationId); - m_graphicsLayer->removeAnimation(animationId); -} - -void CompositedLayerMapping::notifyAnimationStarted(const GraphicsLayer*, double wallClockTime, double monotonicTime) -{ - if (RuntimeEnabledFeatures::webAnimationsCSSEnabled()) - renderer()->node()->document().cssPendingAnimations().notifyCompositorAnimationStarted(monotonicTime); - else - renderer()->animation().notifyAnimationStarted(renderer(), wallClockTime); -} - -IntRect CompositedLayerMapping::compositedBounds() const -{ - return m_compositedBounds; -} - -void CompositedLayerMapping::setCompositedBounds(const IntRect& bounds) -{ - m_compositedBounds = bounds; -} - -void CompositedLayerMapping::addRenderLayerToSquashingGraphicsLayer(RenderLayer* layer, IntSize offsetFromTargetBacking, size_t nextSquashedLayerIndex) -{ - ASSERT(compositor()->layerSquashingEnabled()); - - GraphicsLayerPaintInfo paintInfo; - paintInfo.renderLayer = layer; - // NOTE: composited bounds are updated elsewhere - // NOTE: offsetFromRenderer is updated elsewhere - paintInfo.offsetFromBackingRoot = offsetFromTargetBacking; - paintInfo.paintingPhase = GraphicsLayerPaintAllWithOverflowClip; - paintInfo.isBackgroundLayer = false; - - // Change tracking on squashing layers: at the first sign of something changed, just invalidate the layer. - // FIXME: Perhaps we can find a tighter more clever mechanism later. - if (nextSquashedLayerIndex < m_squashedLayers.size()) { - if (m_squashedLayers[nextSquashedLayerIndex].renderLayer != layer) { - m_squashedLayers[nextSquashedLayerIndex] = paintInfo; - if (m_squashingLayer) - m_squashingLayer->setNeedsDisplay(); - } - } else { - m_squashedLayers.append(paintInfo); - if (m_squashingLayer) - m_squashingLayer->setNeedsDisplay(); - } - layer->setGroupedMapping(this); -} - -void CompositedLayerMapping::finishAccumulatingSquashingLayers(size_t nextSquashedLayerIndex) -{ - ASSERT(compositor()->layerSquashingEnabled()); - - // Any additional squashed RenderLayers in the array no longer exist, and removing invalidates the squashingLayer contents. - if (nextSquashedLayerIndex < m_squashedLayers.size()) { - m_squashedLayers.remove(nextSquashedLayerIndex, m_squashedLayers.size() - nextSquashedLayerIndex); - if (m_squashingLayer) - m_squashingLayer->setNeedsDisplay(); - } -} - -CompositingLayerType CompositedLayerMapping::compositingLayerType() const -{ - if (m_graphicsLayer->hasContentsLayer()) - return MediaCompositingLayer; - - if (m_graphicsLayer->drawsContent()) - return NormalCompositingLayer; - - return ContainerCompositingLayer; -} - -double CompositedLayerMapping::backingStoreMemoryEstimate() const -{ - double backingMemory; - - // m_ancestorClippingLayer and m_childContainmentLayer are just used for masking or containment, so have no backing. - backingMemory = m_graphicsLayer->backingStoreMemoryEstimate(); - if (m_foregroundLayer) - backingMemory += m_foregroundLayer->backingStoreMemoryEstimate(); - if (m_backgroundLayer) - backingMemory += m_backgroundLayer->backingStoreMemoryEstimate(); - if (m_maskLayer) - backingMemory += m_maskLayer->backingStoreMemoryEstimate(); - if (m_childClippingMaskLayer) - backingMemory += m_childClippingMaskLayer->backingStoreMemoryEstimate(); - - if (m_scrollingContentsLayer) - backingMemory += m_scrollingContentsLayer->backingStoreMemoryEstimate(); - - if (m_layerForHorizontalScrollbar) - backingMemory += m_layerForHorizontalScrollbar->backingStoreMemoryEstimate(); - - if (m_layerForVerticalScrollbar) - backingMemory += m_layerForVerticalScrollbar->backingStoreMemoryEstimate(); - - if (m_layerForScrollCorner) - backingMemory += m_layerForScrollCorner->backingStoreMemoryEstimate(); - - return backingMemory; -} - -String CompositedLayerMapping::debugName(const GraphicsLayer* graphicsLayer) -{ - String name; - if (graphicsLayer == m_graphicsLayer.get()) { - name = m_owningLayer->debugName(); - } else if (graphicsLayer == m_ancestorClippingLayer.get()) { - name = "Ancestor Clipping Layer"; - } else if (graphicsLayer == m_foregroundLayer.get()) { - name = m_owningLayer->debugName() + " (foreground) Layer"; - } else if (graphicsLayer == m_backgroundLayer.get()) { - name = m_owningLayer->debugName() + " (background) Layer"; - } else if (graphicsLayer == m_childContainmentLayer.get()) { - name = "Child Containment Layer"; - } else if (graphicsLayer == m_maskLayer.get()) { - name = "Mask Layer"; - } else if (graphicsLayer == m_childClippingMaskLayer.get()) { - name = "Child Clipping Mask Layer"; - } else if (graphicsLayer == m_layerForHorizontalScrollbar.get()) { - name = "Horizontal Scrollbar Layer"; - } else if (graphicsLayer == m_layerForVerticalScrollbar.get()) { - name = "Vertical Scrollbar Layer"; - } else if (graphicsLayer == m_layerForScrollCorner.get()) { - name = "Scroll Corner Layer"; - } else if (graphicsLayer == m_scrollingLayer.get()) { - name = "Scrolling Layer"; - } else if (graphicsLayer == m_scrollingContentsLayer.get()) { - name = "Scrolling Contents Layer"; - } else { - ASSERT_NOT_REACHED(); - } - - return name; -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/CompositingReasons.h b/chromium/third_party/WebKit/Source/core/rendering/CompositingReasons.h deleted file mode 100644 index 8b023a724f8..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/CompositingReasons.h +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CompositingReasons_h -#define CompositingReasons_h - -#include "wtf/MathExtras.h" -#include <stdint.h> - -namespace WebCore { - -const uint64_t CompositingReasonNone = 0; - -// Intrinsic reasons that can be known right away by the layer -const uint64_t CompositingReason3DTransform = UINT64_C(1) << 0; -const uint64_t CompositingReasonVideo = UINT64_C(1) << 1; -const uint64_t CompositingReasonCanvas = UINT64_C(1) << 2; -const uint64_t CompositingReasonPlugin = UINT64_C(1) << 3; -const uint64_t CompositingReasonIFrame = UINT64_C(1) << 4; -const uint64_t CompositingReasonBackfaceVisibilityHidden = UINT64_C(1) << 5; -const uint64_t CompositingReasonAnimation = UINT64_C(1) << 6; -const uint64_t CompositingReasonFilters = UINT64_C(1) << 7; -const uint64_t CompositingReasonPositionFixed = UINT64_C(1) << 8; -const uint64_t CompositingReasonPositionSticky = UINT64_C(1) << 9; -const uint64_t CompositingReasonOverflowScrollingTouch = UINT64_C(1) << 10; - -// Overlap reasons that require knowing what's behind you in paint-order before knowing the answer -const uint64_t CompositingReasonAssumedOverlap = UINT64_C(1) << 12; -const uint64_t CompositingReasonOverlap = UINT64_C(1) << 13; -const uint64_t CompositingReasonNegativeZIndexChildren = UINT64_C(1) << 14; - -// Subtree reasons that require knowing what the status of your subtree is before knowing the answer -const uint64_t CompositingReasonTransformWithCompositedDescendants = UINT64_C(1) << 15; -const uint64_t CompositingReasonOpacityWithCompositedDescendants = UINT64_C(1) << 16; -const uint64_t CompositingReasonMaskWithCompositedDescendants = UINT64_C(1) << 17; -const uint64_t CompositingReasonReflectionWithCompositedDescendants = UINT64_C(1) << 18; -const uint64_t CompositingReasonFilterWithCompositedDescendants = UINT64_C(1) << 19; -const uint64_t CompositingReasonBlendingWithCompositedDescendants = UINT64_C(1) << 20; -const uint64_t CompositingReasonClipsCompositingDescendants = UINT64_C(1) << 21; -const uint64_t CompositingReasonPerspective = UINT64_C(1) << 22; -const uint64_t CompositingReasonPreserve3D = UINT64_C(1) << 23; -const uint64_t CompositingReasonReflectionOfCompositedParent = UINT64_C(1) << 24; - -// The root layer is a special case that may be forced to be a layer, but also it needs to be -// a layer if anything else in the subtree is composited. -const uint64_t CompositingReasonRoot = UINT64_C(1) << 25; - -// CompositedLayerMapping internal hierarchy reasons -const uint64_t CompositingReasonLayerForClip = UINT64_C(1) << 26; -const uint64_t CompositingReasonLayerForScrollbar = UINT64_C(1) << 27; -const uint64_t CompositingReasonLayerForScrollingContainer = UINT64_C(1) << 28; -const uint64_t CompositingReasonLayerForForeground = UINT64_C(1) << 29; -const uint64_t CompositingReasonLayerForBackground = UINT64_C(1) << 30; -const uint64_t CompositingReasonLayerForMask = UINT64_C(1) << 31; - -// FIXME: the following compositing reasons need to be re-organized to fit with categories -// used in all the other reasons above. -const uint64_t CompositingReasonOverflowScrollingParent = UINT64_C(1) << 32; -const uint64_t CompositingReasonOutOfFlowClipping = UINT64_C(1) << 33; - -const uint64_t CompositingReasonLayerForVideoOverlay = UINT64_C(1) << 34; -const uint64_t CompositingReasonIsolateCompositedDescendants = UINT64_C(1) << 35; - -// Note: if you add more reasons here, you will need to update WebCompositingReasons as well. - -// Various combinations of compositing reasons are defined here also, for more intutive and faster bitwise logic. -const uint64_t CompositingReasonComboAllDirectReasons = - CompositingReason3DTransform - | CompositingReasonVideo - | CompositingReasonCanvas - | CompositingReasonPlugin - | CompositingReasonIFrame - | CompositingReasonBackfaceVisibilityHidden - | CompositingReasonAnimation - | CompositingReasonFilters - | CompositingReasonPositionFixed - | CompositingReasonPositionSticky - | CompositingReasonOverflowScrollingTouch - | CompositingReasonOverflowScrollingParent - | CompositingReasonOutOfFlowClipping; - -const uint64_t CompositingReasonComboReasonsThatRequireOwnBacking = - CompositingReasonComboAllDirectReasons - | CompositingReasonOverlap - | CompositingReasonAssumedOverlap - | CompositingReasonNegativeZIndexChildren - | CompositingReasonTransformWithCompositedDescendants - | CompositingReasonOpacityWithCompositedDescendants - | CompositingReasonMaskWithCompositedDescendants - | CompositingReasonFilterWithCompositedDescendants - | CompositingReasonBlendingWithCompositedDescendants - | CompositingReasonIsolateCompositedDescendants - | CompositingReasonPreserve3D; // preserve-3d has to create backing store to ensure that 3d-transformed elements intersect. - -const uint64_t CompositingReasonComboAllOverlapReasons = - CompositingReasonOverlap - | CompositingReasonAssumedOverlap; - -typedef uint64_t CompositingReasons; - - -} // namespace WebCore - -#endif // CompositingReasons_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/EllipsisBox.cpp b/chromium/third_party/WebKit/Source/core/rendering/EllipsisBox.cpp index 9051eb20342..9f3e0262827 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/EllipsisBox.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/EllipsisBox.cpp @@ -27,7 +27,7 @@ #include "core/rendering/RootInlineBox.h" #include "core/rendering/style/ShadowList.h" #include "platform/fonts/Font.h" -#include "platform/graphics/DrawLooper.h" +#include "platform/graphics/DrawLooperBuilder.h" #include "platform/graphics/GraphicsContextStateSaver.h" #include "platform/text/TextRun.h" @@ -36,21 +36,20 @@ namespace WebCore { void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { GraphicsContext* context = paintInfo.context; - RenderStyle* style = m_renderer->style(isFirstLineStyle()); + RenderStyle* style = renderer().style(isFirstLineStyle()); const Font& font = style->font(); FloatPoint boxOrigin = locationIncludingFlipping(); - LayoutPoint adjustedPaintOffset = paintOffset; + boxOrigin.moveBy(FloatPoint(paintOffset)); if (!isHorizontal()) - adjustedPaintOffset.move(0, -virtualLogicalHeight()); - boxOrigin.move(adjustedPaintOffset.x(), adjustedPaintOffset.y()); + boxOrigin.move(0, -virtualLogicalHeight()); FloatRect boxRect(boxOrigin, LayoutSize(logicalWidth(), virtualLogicalHeight())); GraphicsContextStateSaver stateSaver(*context); if (!isHorizontal()) context->concatCTM(InlineTextBox::rotation(boxRect, InlineTextBox::Clockwise)); FloatPoint textOrigin = FloatPoint(boxOrigin.x(), boxOrigin.y() + font.fontMetrics().ascent()); - Color styleTextColor = m_renderer->resolveColor(style, CSSPropertyWebkitTextFillColor); + Color styleTextColor = renderer().resolveColor(style, CSSPropertyWebkitTextFillColor); if (styleTextColor != context->fillColor()) context->setFillColor(styleTextColor); @@ -58,8 +57,8 @@ void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, La paintSelection(context, boxOrigin, style, font); // Select the correct color for painting the text. - Color foreground = paintInfo.forceBlackText() ? Color::black : renderer()->selectionForegroundColor(); - if (foreground.isValid() && foreground != styleTextColor) + Color foreground = paintInfo.forceBlackText() ? Color::black : renderer().selectionForegroundColor(); + if (foreground != styleTextColor) context->setFillColor(foreground); } @@ -67,21 +66,20 @@ void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, La const ShadowList* shadowList = context->printing() ? 0 : style->textShadow(); bool hasShadow = shadowList; if (hasShadow) { - DrawLooper drawLooper; + OwnPtr<DrawLooperBuilder> drawLooperBuilder = DrawLooperBuilder::create(); for (size_t i = shadowList->shadows().size(); i--; ) { const ShadowData& shadow = shadowList->shadows()[i]; - int shadowX = isHorizontal() ? shadow.x() : shadow.y(); - int shadowY = isHorizontal() ? shadow.y() : -shadow.x(); + float shadowX = isHorizontal() ? shadow.x() : shadow.y(); + float shadowY = isHorizontal() ? shadow.y() : -shadow.x(); FloatSize offset(shadowX, shadowY); - drawLooper.addShadow(offset, shadow.blur(), m_renderer->resolveColor(shadow.color()), - DrawLooper::ShadowRespectsTransforms, DrawLooper::ShadowIgnoresAlpha); + drawLooperBuilder->addShadow(offset, shadow.blur(), shadow.color(), + DrawLooperBuilder::ShadowRespectsTransforms, DrawLooperBuilder::ShadowIgnoresAlpha); } - drawLooper.addUnmodifiedContent(); - context->setDrawLooper(drawLooper); + drawLooperBuilder->addUnmodifiedContent(); + context->setDrawLooper(drawLooperBuilder.release()); } - // FIXME: Why is this always LTR? Fix by passing correct text run flags below. - TextRun textRun = RenderBlockFlow::constructTextRun(renderer(), font, m_str, style, TextRun::AllowTrailingExpansion); + TextRun textRun = RenderBlockFlow::constructTextRun(&renderer(), font, m_str, style, TextRun::AllowTrailingExpansion); TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.bounds = boxRect; context->drawText(font, textRunPaintInfo, textOrigin); @@ -98,18 +96,18 @@ void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, La InlineBox* EllipsisBox::markupBox() const { - if (!m_shouldPaintMarkupBox || !m_renderer->isRenderBlock()) + if (!m_shouldPaintMarkupBox || !renderer().isRenderBlock()) return 0; - RenderBlock* block = toRenderBlock(m_renderer); - RootInlineBox* lastLine = block->lineAtIndex(block->lineCount() - 1); + RenderBlock& block = toRenderBlock(renderer()); + RootInlineBox* lastLine = block.lineAtIndex(block.lineCount() - 1); if (!lastLine) return 0; // If the last line-box on the last line of a block is a link, -webkit-line-clamp paints that box after the ellipsis. // It does not actually move the link. InlineBox* anchorBox = lastLine->lastChild(); - if (!anchorBox || !anchorBox->renderer()->style()->isLink()) + if (!anchorBox || !anchorBox->renderer().style()->isLink()) return 0; return anchorBox; @@ -123,23 +121,22 @@ void EllipsisBox::paintMarkupBox(PaintInfo& paintInfo, const LayoutPoint& paintO LayoutPoint adjustedPaintOffset = paintOffset; adjustedPaintOffset.move(x() + m_logicalWidth - markupBox->x(), - y() + style->fontMetrics().ascent() - (markupBox->y() + markupBox->renderer()->style(isFirstLineStyle())->fontMetrics().ascent())); + y() + style->fontMetrics().ascent() - (markupBox->y() + markupBox->renderer().style(isFirstLineStyle())->fontMetrics().ascent())); markupBox->paint(paintInfo, adjustedPaintOffset, lineTop, lineBottom); } IntRect EllipsisBox::selectionRect() { - RenderStyle* style = m_renderer->style(isFirstLineStyle()); + RenderStyle* style = 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(RenderBlockFlow::constructTextRun(renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), IntPoint(logicalLeft(), logicalTop() + root()->selectionTopAdjustedForPrecedingBlock()), root()->selectionHeightAdjustedForPrecedingBlock())); + return enclosingIntRect(font.selectionRectForText(RenderBlockFlow::constructTextRun(&renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), IntPoint(logicalLeft(), logicalTop() + root().selectionTopAdjustedForPrecedingBlock()), root().selectionHeightAdjustedForPrecedingBlock())); } void EllipsisBox::paintSelection(GraphicsContext* context, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font) { - Color textColor = m_renderer->resolveColor(style, CSSPropertyColor); - Color c = m_renderer->selectionBackgroundColor(); - if (!c.isValid() || !c.alpha()) + Color textColor = renderer().resolveColor(style, CSSPropertyColor); + Color c = renderer().selectionBackgroundColor(); + if (!c.alpha()) return; // If the text color ends up being the same as the selection background, invert the selection @@ -148,16 +145,15 @@ void EllipsisBox::paintSelection(GraphicsContext* context, const FloatPoint& box c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue()); GraphicsContextStateSaver stateSaver(*context); - LayoutUnit selectionBottom = root()->selectionBottom(); - LayoutUnit top = root()->selectionTop(); - LayoutUnit h = root()->selectionHeight(); - const int deltaY = roundToInt(renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom - logicalBottom() : logicalTop() - top); + LayoutUnit selectionBottom = root().selectionBottom(); + LayoutUnit top = root().selectionTop(); + LayoutUnit h = root().selectionHeight(); + const int deltaY = roundToInt(renderer().style()->isFlippedLinesWritingMode() ? selectionBottom - logicalBottom() : logicalTop() - top); const FloatPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY); - FloatRect clipRect(localOrigin, FloatSize(m_logicalWidth, h)); + FloatRect clipRect(localOrigin, FloatSize(m_logicalWidth, h.toFloat())); alignSelectionRectToDevicePixels(clipRect); context->clip(clipRect); - // FIXME: Why is this always LTR? Fix by passing correct text run flags below. - context->drawHighlightForText(font, RenderBlockFlow::constructTextRun(renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), localOrigin, h, c); + context->drawHighlightForText(font, RenderBlockFlow::constructTextRun(&renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), localOrigin, h, c); } bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) @@ -166,11 +162,11 @@ bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu // Hit test the markup box. if (InlineBox* markupBox = this->markupBox()) { - RenderStyle* style = m_renderer->style(isFirstLineStyle()); + RenderStyle* style = renderer().style(isFirstLineStyle()); LayoutUnit mtx = adjustedLocation.x() + m_logicalWidth - markupBox->x(); - LayoutUnit mty = adjustedLocation.y() + style->fontMetrics().ascent() - (markupBox->y() + markupBox->renderer()->style(isFirstLineStyle())->fontMetrics().ascent()); + LayoutUnit mty = adjustedLocation.y() + style->fontMetrics().ascent() - (markupBox->y() + markupBox->renderer().style(isFirstLineStyle())->fontMetrics().ascent()); if (markupBox->nodeAtPoint(request, result, locationInContainer, LayoutPoint(mtx, mty), lineTop, lineBottom)) { - renderer()->updateHitTestResult(result, locationInContainer.point() - LayoutSize(mtx, mty)); + renderer().updateHitTestResult(result, locationInContainer.point() - LayoutSize(mtx, mty)); return true; } } @@ -179,8 +175,8 @@ bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu boxOrigin.moveBy(accumulatedOffset); FloatRect boundsRect(boxOrigin, size()); if (visibleToHitTestRequest(request) && boundsRect.intersects(HitTestLocation::rectForPoint(locationInContainer.point(), 0, 0, 0, 0))) { - renderer()->updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation)); - if (!result.addNodeToRectBasedTestResult(renderer()->node(), request, locationInContainer, boundsRect)) + renderer().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation)); + if (!result.addNodeToRectBasedTestResult(renderer().node(), request, locationInContainer, boundsRect)) return true; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/EllipsisBox.h b/chromium/third_party/WebKit/Source/core/rendering/EllipsisBox.h index ad8e61291f5..c97d375c54a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/EllipsisBox.h +++ b/chromium/third_party/WebKit/Source/core/rendering/EllipsisBox.h @@ -29,7 +29,7 @@ class HitTestResult; class EllipsisBox FINAL : public InlineBox { public: - EllipsisBox(RenderObject* obj, const AtomicString& ellipsisStr, InlineFlowBox* parent, + EllipsisBox(RenderObject& obj, const AtomicString& ellipsisStr, InlineFlowBox* parent, int width, int height, int x, int y, bool firstLine, bool isVertical, InlineBox* markupBox) : InlineBox(obj, FloatPoint(x, y), width, firstLine, true, false, false, isVertical, 0, 0, parent) , m_shouldPaintMarkupBox(markupBox) @@ -40,7 +40,7 @@ public: setHasVirtualLogicalHeight(); } - virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); + virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; void setSelectionState(RenderObject::SelectionState s) { m_selectionState = s; } IntRect selectionRect(); @@ -48,8 +48,8 @@ public: virtual float virtualLogicalHeight() const OVERRIDE { return m_height; } private: void paintMarkupBox(PaintInfo&, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom, RenderStyle*); - virtual int height() const { return m_height; } - virtual RenderObject::SelectionState selectionState() { return m_selectionState; } + int height() const { return m_height; } + virtual RenderObject::SelectionState selectionState() OVERRIDE { return m_selectionState; } void paintSelection(GraphicsContext*, const FloatPoint&, RenderStyle*, const Font&); InlineBox* markupBox() const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/FastTextAutosizer.cpp b/chromium/third_party/WebKit/Source/core/rendering/FastTextAutosizer.cpp index cbdcafc68f0..43ec0362bf6 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/FastTextAutosizer.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/FastTextAutosizer.cpp @@ -32,108 +32,1100 @@ #include "core/rendering/FastTextAutosizer.h" #include "core/dom/Document.h" +#include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/frame/Settings.h" +#include "core/html/HTMLTextAreaElement.h" +#include "core/page/Page.h" #include "core/rendering/InlineIterator.h" #include "core/rendering/RenderBlock.h" -#include "core/rendering/TextAutosizer.h" +#include "core/rendering/RenderListItem.h" +#include "core/rendering/RenderListMarker.h" +#include "core/rendering/RenderTableCell.h" +#include "core/rendering/RenderView.h" + +#ifdef AUTOSIZING_DOM_DEBUG_INFO +#include "core/dom/ExecutionContextTask.h" +#endif + +using namespace std; namespace WebCore { -FastTextAutosizer::FastTextAutosizer(Document* document) +#ifdef AUTOSIZING_DOM_DEBUG_INFO +class WriteDebugInfoTask : public ExecutionContextTask { +public: + WriteDebugInfoTask(PassRefPtrWillBeRawPtr<Element> element, AtomicString value) + : m_element(element) + , m_value(value) + { + } + + virtual void performTask(ExecutionContext*) + { + m_element->setAttribute("data-autosizing", m_value, ASSERT_NO_EXCEPTION); + } + +private: + RefPtrWillBePersistent<Element> m_element; + AtomicString m_value; +}; + +static void writeDebugInfo(RenderObject* renderer, const AtomicString& output) +{ + Node* node = renderer->node(); + if (!node) + return; + if (node->isDocumentNode()) + node = toDocument(node)->documentElement(); + if (!node->isElementNode()) + return; + node->document().postTask(adoptPtr(new WriteDebugInfoTask(toElement(node), output))); +} + +void FastTextAutosizer::writeClusterDebugInfo(Cluster* cluster) +{ + String explanation = ""; + if (cluster->m_flags & SUPPRESSING) { + explanation = "[suppressed]"; + } else if (!(cluster->m_flags & (INDEPENDENT | WIDER_OR_NARROWER))) { + explanation = "[inherited]"; + } else if (cluster->m_supercluster) { + explanation = "[supercluster]"; + } else if (!clusterHasEnoughTextToAutosize(cluster)) { + explanation = "[insufficient-text]"; + } else { + const RenderBlock* widthProvider = clusterWidthProvider(cluster->m_root); + if (cluster->m_hasTableAncestor && cluster->m_multiplier < multiplierFromBlock(widthProvider)) { + explanation = "[table-ancestor-limited]"; + } else { + explanation = String::format("[from width %d of %s]", + static_cast<int>(widthFromBlock(widthProvider)), widthProvider->debugName().utf8().data()); + } + } + String pageInfo = ""; + if (cluster->m_root->isRenderView()) { + pageInfo = String::format("; pageinfo: bm %f * (lw %d / fw %d)", + m_pageInfo.m_baseMultiplier, m_pageInfo.m_layoutWidth, m_pageInfo.m_frameWidth); + } + float multiplier = cluster->m_flags & SUPPRESSING ? 1.0 : cluster->m_multiplier; + writeDebugInfo(const_cast<RenderBlock*>(cluster->m_root), + AtomicString(String::format("cluster: %f %s%s", multiplier, + explanation.utf8().data(), pageInfo.utf8().data()))); +} +#endif + +static const RenderObject* parentElementRenderer(const RenderObject* renderer) +{ + // At style recalc, the renderer's parent may not be attached, + // so we need to obtain this from the DOM tree. + const Node* node = renderer->node(); + if (!node) + return 0; + + while ((node = node->parentNode())) { + if (node->isElementNode()) + return node->renderer(); + } + return 0; +} + +static bool isNonTextAreaFormControl(const RenderObject* renderer) +{ + const Node* node = renderer ? renderer->node() : 0; + if (!node || !node->isElementNode()) + return false; + const Element* element = toElement(node); + + return (element->isFormControlElement() && !isHTMLTextAreaElement(element)); +} + +static bool isPotentialClusterRoot(const RenderObject* renderer) +{ + // "Potential cluster roots" are the smallest unit for which we can + // enable/disable text autosizing. + // - Must not be inline, as different multipliers on one line looks terrible. + // Exceptions are inline-block and alike elements (inline-table, -webkit-inline-*), + // as they often contain entire multi-line columns of text. + // - Must not be normal list items, as items in the same list should look + // consistent, unless they are floating or position:absolute/fixed. + Node* node = renderer->generatingNode(); + if (node && !node->hasChildren()) + return false; + if (!renderer->isRenderBlock()) + return false; + if (renderer->isInline() && !renderer->style()->isDisplayReplacedType()) + return false; + if (renderer->isListItem()) + return (renderer->isFloating() || renderer->isOutOfFlowPositioned()); + + return true; +} + +static bool isIndependentDescendant(const RenderBlock* renderer) +{ + ASSERT(isPotentialClusterRoot(renderer)); + + RenderBlock* containingBlock = renderer->containingBlock(); + return renderer->isRenderView() + || renderer->isFloating() + || renderer->isOutOfFlowPositioned() + || renderer->isTableCell() + || renderer->isTableCaption() + || renderer->isFlexibleBoxIncludingDeprecated() + || renderer->hasColumns() + || (containingBlock && containingBlock->isHorizontalWritingMode() != renderer->isHorizontalWritingMode()) + || renderer->style()->isDisplayReplacedType() + || renderer->isTextArea() + || renderer->style()->userModify() != READ_ONLY; +} + +static bool blockIsRowOfLinks(const RenderBlock* block) +{ + // A "row of links" is a block for which: + // 1. It does not contain non-link text elements longer than 3 characters + // 2. It contains a minimum of 3 inline links and all links should + // have the same specified font size. + // 3. It should not contain <br> elements. + // 4. It should contain only inline elements unless they are containers, + // children of link elements or children of sub-containers. + int linkCount = 0; + RenderObject* renderer = block->firstChild(); + float matchingFontSize = -1; + + while (renderer) { + if (!isPotentialClusterRoot(renderer)) { + if (renderer->isText() && toRenderText(renderer)->text().impl()->stripWhiteSpace()->length() > 3) + return false; + if (!renderer->isInline() || renderer->isBR()) + return false; + } + if (renderer->style()->isLink()) { + linkCount++; + if (matchingFontSize < 0) + matchingFontSize = renderer->style()->specifiedFontSize(); + else if (matchingFontSize != renderer->style()->specifiedFontSize()) + return false; + + // Skip traversing descendants of the link. + renderer = renderer->nextInPreOrderAfterChildren(block); + continue; + } + renderer = renderer->nextInPreOrder(block); + } + + return (linkCount >= 3); +} + +static bool blockHeightConstrained(const RenderBlock* block) +{ + // FIXME: Propagate constrainedness down the tree, to avoid inefficiently walking back up from each box. + // FIXME: This code needs to take into account vertical writing modes. + // FIXME: Consider additional heuristics, such as ignoring fixed heights if the content is already overflowing before autosizing kicks in. + for (; block; block = block->containingBlock()) { + RenderStyle* style = block->style(); + if (style->overflowY() >= OSCROLL) + return false; + if (style->height().isSpecified() || style->maxHeight().isSpecified() || block->isOutOfFlowPositioned()) { + // Some sites (e.g. wikipedia) set their html and/or body elements to height:100%, + // without intending to constrain the height of the content within them. + return !block->isDocumentElement() && !block->isBody(); + } + if (block->isFloating()) + return false; + } + return false; +} + +static bool blockOrImmediateChildrenAreFormControls(const RenderBlock* block) +{ + if (isNonTextAreaFormControl(block)) + return true; + const RenderObject* renderer = block->firstChild(); + while (renderer) { + if (isNonTextAreaFormControl(renderer)) + return true; + renderer = renderer->nextSibling(); + } + + return false; +} + +// Some blocks are not autosized even if their parent cluster wants them to. +static bool blockSuppressesAutosizing(const RenderBlock* block) +{ + if (blockOrImmediateChildrenAreFormControls(block)) + return true; + + if (blockIsRowOfLinks(block)) + return true; + + // Don't autosize block-level text that can't wrap (as it's likely to + // expand sideways and break the page's layout). + if (!block->style()->autoWrap()) + return true; + + if (blockHeightConstrained(block)) + return true; + + return false; +} + +static bool hasExplicitWidth(const RenderBlock* block) +{ + // FIXME: This heuristic may need to be expanded to other ways a block can be wider or narrower + // than its parent containing block. + return block->style() && block->style()->width().isSpecified(); +} + +FastTextAutosizer::FastTextAutosizer(const Document* document) : m_document(document) + , m_firstBlockToBeginLayout(0) +#ifndef NDEBUG + , m_blocksThatHaveBegunLayout() +#endif + , m_superclusters() + , m_clusterStack() + , m_fingerprintMapper() + , m_pageInfo() + , m_updatePageInfoDeferred(false) { } void FastTextAutosizer::record(const RenderBlock* block) { - if (!m_document->settings() - || !m_document->settings()->textAutosizingEnabled() - || m_document->printing() - || !m_document->page()) + if (!m_pageInfo.m_settingEnabled) return; - if (!TextAutosizer::isAutosizingContainer(block)) + ASSERT(!m_blocksThatHaveBegunLayout.contains(block)); + + if (!classifyBlock(block, INDEPENDENT | EXPLICIT_WIDTH)) return; - AtomicString blockFingerprint = fingerprint(block); - HashMap<AtomicString, OwnPtr<Cluster> >::AddResult result = - m_clusterForFingerprint.add(blockFingerprint, PassOwnPtr<Cluster>()); + if (Fingerprint fingerprint = computeFingerprint(block)) + m_fingerprintMapper.addTentativeClusterRoot(block, fingerprint); +} - if (result.isNewEntry) - result.iterator->value = adoptPtr(new Cluster(blockFingerprint)); +void FastTextAutosizer::destroy(const RenderBlock* block) +{ + if (!m_pageInfo.m_settingEnabled) + return; - Cluster* cluster = result.iterator->value.get(); - cluster->m_blocks.add(block); + ASSERT(!m_blocksThatHaveBegunLayout.contains(block)); - m_clusterForBlock.set(block, cluster); + if (m_fingerprintMapper.remove(block) && m_firstBlockToBeginLayout) { + // RenderBlock with a fingerprint was destroyed during layout. + // Clear the cluster stack and the supercluster map to avoid stale pointers. + // Speculative fix for http://crbug.com/369485. + m_firstBlockToBeginLayout = 0; + m_clusterStack.clear(); + m_superclusters.clear(); + } } -void FastTextAutosizer::destroy(const RenderBlock* block) +FastTextAutosizer::BeginLayoutBehavior FastTextAutosizer::prepareForLayout(const RenderBlock* block) { - Cluster* cluster = m_clusterForBlock.take(block); - if (!cluster) +#ifndef NDEBUG + m_blocksThatHaveBegunLayout.add(block); +#endif + + if (!m_firstBlockToBeginLayout) { + m_firstBlockToBeginLayout = block; + prepareClusterStack(block->parent()); + } else if (block == currentCluster()->m_root) { + // Ignore beginLayout on the same block twice. + // This can happen with paginated overflow. + return StopLayout; + } + + return ContinueLayout; +} + +void FastTextAutosizer::prepareClusterStack(const RenderObject* renderer) +{ + if (!renderer) return; - cluster->m_blocks.remove(block); - if (cluster->m_blocks.isEmpty()) { - // This deletes the Cluster. - m_clusterForFingerprint.remove(cluster->m_fingerprint); + prepareClusterStack(renderer->parent()); + + if (renderer->isRenderBlock()) { + const RenderBlock* block = toRenderBlock(renderer); +#ifndef NDEBUG + m_blocksThatHaveBegunLayout.add(block); +#endif + if (Cluster* cluster = maybeCreateCluster(block)) + m_clusterStack.append(adoptPtr(cluster)); + } +} + +void FastTextAutosizer::beginLayout(RenderBlock* block) +{ + ASSERT(shouldHandleLayout()); + + if (prepareForLayout(block) == StopLayout) + return; + + if (Cluster* cluster = maybeCreateCluster(block)) + m_clusterStack.append(adoptPtr(cluster)); + + // Cells in auto-layout tables are handled separately by inflateAutoTable. + bool isAutoTableCell = block->isTableCell() && !toRenderTableCell(block)->table()->style()->isFixedTableLayout(); + if (!isAutoTableCell && !m_clusterStack.isEmpty()) + inflate(block); +} + +void FastTextAutosizer::inflateListItem(RenderListItem* listItem, RenderListMarker* listItemMarker) +{ + if (!shouldHandleLayout()) return; + ASSERT(listItem && listItemMarker); + + if (prepareForLayout(listItem) == StopLayout) + return; + + // Force the LI to be inside the DBCAT when computing the multiplier. + // This guarantees that the DBCAT has entered layout, so we can ask for its width. + // It also makes sense because the list marker is autosized like a text node. + float multiplier = clusterMultiplier(currentCluster()); + + applyMultiplier(listItem, multiplier); + applyMultiplier(listItemMarker, multiplier); +} + +void FastTextAutosizer::inflateAutoTable(RenderTable* table) +{ + ASSERT(table); + ASSERT(!table->style()->isFixedTableLayout()); + ASSERT(table->containingBlock()); + + Cluster* cluster = currentCluster(); + if (cluster->m_root != table) + return; + + // Pre-inflate cells that have enough text so that their inflated preferred widths will be used + // for column sizing. + for (RenderObject* section = table->firstChild(); section; section = section->nextSibling()) { + if (!section->isTableSection()) + continue; + for (RenderTableRow* row = toRenderTableSection(section)->firstRow(); row; row = row->nextRow()) { + for (RenderTableCell* cell = row->firstCell(); cell; cell = cell->nextCell()) { + if (!cell->needsLayout()) + continue; + + beginLayout(cell); + inflate(cell, DescendToInnerBlocks); + endLayout(cell); + } + } } - cluster->m_multiplier = 0; } -static void applyMultiplier(RenderObject* renderer, float multiplier) +void FastTextAutosizer::endLayout(RenderBlock* block) { - // We need to clone the render style to avoid breaking style sharing. - RefPtr<RenderStyle> style = RenderStyle::clone(renderer->style()); - style->setTextAutosizingMultiplier(multiplier); - style->setUnique(); - renderer->setStyleInternal(style.release()); + ASSERT(shouldHandleLayout()); + + if (block == m_firstBlockToBeginLayout) { + m_firstBlockToBeginLayout = 0; + m_clusterStack.clear(); + m_superclusters.clear(); + m_stylesRetainedDuringLayout.clear(); +#ifndef NDEBUG + m_blocksThatHaveBegunLayout.clear(); +#endif + // Tables can create two layout scopes for the same block so the isEmpty + // check below is needed to guard against endLayout being called twice. + } else if (!m_clusterStack.isEmpty() && currentCluster()->m_root == block) { + m_clusterStack.removeLast(); + } } -void FastTextAutosizer::inflate(RenderBlock* block) +float FastTextAutosizer::inflate(RenderObject* parent, InflateBehavior behavior, float multiplier) { - Cluster* cluster = 0; - for (const RenderObject* clusterBlock = block; clusterBlock && !cluster; clusterBlock = clusterBlock->parent()) { - if (clusterBlock->isRenderBlock()) - cluster = m_clusterForBlock.get(toRenderBlock(clusterBlock)); + Cluster* cluster = currentCluster(); + bool hasTextChild = false; + + RenderObject* child = 0; + if (parent->isRenderBlock() && (parent->childrenInline() || behavior == DescendToInnerBlocks)) + child = toRenderBlock(parent)->firstChild(); + else if (parent->isRenderInline()) + child = toRenderInline(parent)->firstChild(); + + while (child) { + if (child->isText()) { + hasTextChild = true; + // We only calculate this multiplier on-demand to ensure the parent block of this text + // has entered layout. + if (!multiplier) + multiplier = cluster->m_flags & SUPPRESSING ? 1.0f : clusterMultiplier(cluster); + applyMultiplier(child, multiplier); + // FIXME: Investigate why MarkOnlyThis is sufficient. + if (parent->isRenderInline()) + child->setPreferredLogicalWidthsDirty(MarkOnlyThis); + } else if (child->isRenderInline()) { + multiplier = inflate(child, behavior, multiplier); + } else if (child->isRenderBlock() && behavior == DescendToInnerBlocks + && !classifyBlock(child, INDEPENDENT | EXPLICIT_WIDTH | SUPPRESSING)) { + multiplier = inflate(child, behavior, multiplier); + } + child = child->nextSibling(); } - if (!cluster) - return; - if (!cluster->m_multiplier) - cluster->m_multiplier = computeMultiplier(cluster); - if (cluster->m_multiplier == 1) + + if (hasTextChild) { + applyMultiplier(parent, multiplier); // Parent handles line spacing. + } else if (!parent->isListItem()) { + // For consistency, a block with no immediate text child should always have a + // multiplier of 1 (except for list items which are handled in inflateListItem). + applyMultiplier(parent, 1); + } + return multiplier; +} + +bool FastTextAutosizer::shouldHandleLayout() const +{ + return m_pageInfo.m_settingEnabled && m_pageInfo.m_pageNeedsAutosizing && !m_updatePageInfoDeferred; +} + +void FastTextAutosizer::updatePageInfoInAllFrames() +{ + ASSERT(!m_document->frame() || m_document->frame()->isMainFrame()); + + for (Frame* frame = m_document->frame(); frame; frame = frame->tree().traverseNext()) { + if (!frame->isLocalFrame()) + continue; + if (FastTextAutosizer* textAutosizer = toLocalFrame(frame)->document()->fastTextAutosizer()) + textAutosizer->updatePageInfo(); + } +} + +void FastTextAutosizer::updatePageInfo() +{ + if (m_updatePageInfoDeferred || !m_document->page() || !m_document->settings()) return; - applyMultiplier(block, cluster->m_multiplier); - for (InlineWalker walker(block); !walker.atEnd(); walker.advance()) { - RenderObject* inlineObj = walker.current(); - if (inlineObj->isRenderBlock() && m_clusterForBlock.contains(toRenderBlock(inlineObj))) + PageInfo previousPageInfo(m_pageInfo); + m_pageInfo.m_settingEnabled = m_document->settings()->textAutosizingEnabled(); + + if (!m_pageInfo.m_settingEnabled || m_document->printing()) { + m_pageInfo.m_pageNeedsAutosizing = false; + } else { + RenderView* renderView = m_document->renderView(); + bool horizontalWritingMode = isHorizontalWritingMode(renderView->style()->writingMode()); + + LocalFrame* mainFrame = m_document->page()->deprecatedLocalMainFrame(); + IntSize frameSize = m_document->settings()->textAutosizingWindowSizeOverride(); + if (frameSize.isEmpty()) + frameSize = mainFrame->view()->unscaledVisibleContentSize(IncludeScrollbars); + m_pageInfo.m_frameWidth = horizontalWritingMode ? frameSize.width() : frameSize.height(); + + IntSize layoutSize = mainFrame->view()->layoutSize(); + m_pageInfo.m_layoutWidth = horizontalWritingMode ? layoutSize.width() : layoutSize.height(); + + // Compute the base font scale multiplier based on device and accessibility settings. + m_pageInfo.m_baseMultiplier = m_document->settings()->accessibilityFontScaleFactor(); + // If the page has a meta viewport or @viewport, don't apply the device scale adjustment. + const ViewportDescription& viewportDescription = mainFrame->document()->viewportDescription(); + if (!viewportDescription.isSpecifiedByAuthor()) { + float deviceScaleAdjustment = m_document->settings()->deviceScaleAdjustment(); + m_pageInfo.m_baseMultiplier *= deviceScaleAdjustment; + } + + m_pageInfo.m_pageNeedsAutosizing = !!m_pageInfo.m_frameWidth + && (m_pageInfo.m_baseMultiplier * (static_cast<float>(m_pageInfo.m_layoutWidth) / m_pageInfo.m_frameWidth) > 1.0f); + } + + if (m_pageInfo.m_pageNeedsAutosizing) { + // If page info has changed, multipliers may have changed. Force a layout to recompute them. + if (m_pageInfo.m_frameWidth != previousPageInfo.m_frameWidth + || m_pageInfo.m_layoutWidth != previousPageInfo.m_layoutWidth + || m_pageInfo.m_baseMultiplier != previousPageInfo.m_baseMultiplier + || m_pageInfo.m_settingEnabled != previousPageInfo.m_settingEnabled) + setAllTextNeedsLayout(); + } else if (previousPageInfo.m_hasAutosized) { + // If we are no longer autosizing the page, we won't do anything during the next layout. + // Set all the multipliers back to 1 now. + resetMultipliers(); + m_pageInfo.m_hasAutosized = false; + } +} + +void FastTextAutosizer::resetMultipliers() +{ + RenderObject* renderer = m_document->renderView(); + while (renderer) { + if (RenderStyle* style = renderer->style()) { + if (style->textAutosizingMultiplier() != 1) + applyMultiplier(renderer, 1, LayoutNeeded); + } + renderer = renderer->nextInPreOrder(); + } +} + +void FastTextAutosizer::setAllTextNeedsLayout() +{ + RenderObject* renderer = m_document->renderView(); + while (renderer) { + if (renderer->isText()) + renderer->setNeedsLayoutAndFullPaintInvalidation(); + renderer = renderer->nextInPreOrder(); + } +} + +FastTextAutosizer::BlockFlags FastTextAutosizer::classifyBlock(const RenderObject* renderer, BlockFlags mask) +{ + if (!renderer->isRenderBlock()) + return 0; + + const RenderBlock* block = toRenderBlock(renderer); + BlockFlags flags = 0; + + if (isPotentialClusterRoot(block)) { + if (mask & POTENTIAL_ROOT) + flags |= POTENTIAL_ROOT; + + if ((mask & INDEPENDENT) && (isIndependentDescendant(block) || block->isTable())) + flags |= INDEPENDENT; + + if ((mask & EXPLICIT_WIDTH) && hasExplicitWidth(block)) + flags |= EXPLICIT_WIDTH; + + if ((mask & SUPPRESSING) && blockSuppressesAutosizing(block)) + flags |= SUPPRESSING; + } + return flags; +} + +bool FastTextAutosizer::clusterWouldHaveEnoughTextToAutosize(const RenderBlock* root, const RenderBlock* widthProvider) +{ + Cluster hypotheticalCluster(root, classifyBlock(root), 0); + return clusterHasEnoughTextToAutosize(&hypotheticalCluster, widthProvider); +} + +bool FastTextAutosizer::clusterHasEnoughTextToAutosize(Cluster* cluster, const RenderBlock* widthProvider) +{ + if (cluster->m_hasEnoughTextToAutosize != UnknownAmountOfText) + return cluster->m_hasEnoughTextToAutosize == HasEnoughText; + + const RenderBlock* root = cluster->m_root; + if (!widthProvider) + widthProvider = clusterWidthProvider(root); + + // TextAreas and user-modifiable areas get a free pass to autosize regardless of text content. + if (root->isTextArea() || (root->style() && root->style()->userModify() != READ_ONLY)) { + cluster->m_hasEnoughTextToAutosize = HasEnoughText; + return true; + } + + if (cluster->m_flags & SUPPRESSING) { + cluster->m_hasEnoughTextToAutosize = NotEnoughText; + return false; + } + + // 4 lines of text is considered enough to autosize. + float minimumTextLengthToAutosize = widthFromBlock(widthProvider) * 4; + + float length = 0; + RenderObject* descendant = root->firstChild(); + while (descendant) { + if (descendant->isRenderBlock()) { + if (classifyBlock(descendant, INDEPENDENT | SUPPRESSING)) { + descendant = descendant->nextInPreOrderAfterChildren(root); + continue; + } + } else if (descendant->isText()) { + // Note: Using text().stripWhiteSpace().length() instead of renderedTextLength() because + // the lineboxes will not be built until layout. These values can be different. + // Note: This is an approximation assuming each character is 1em wide. + length += toRenderText(descendant)->text().stripWhiteSpace().length() * descendant->style()->specifiedFontSize(); + + if (length >= minimumTextLengthToAutosize) { + cluster->m_hasEnoughTextToAutosize = HasEnoughText; + return true; + } + } + descendant = descendant->nextInPreOrder(root); + } + + cluster->m_hasEnoughTextToAutosize = NotEnoughText; + return false; +} + +FastTextAutosizer::Fingerprint FastTextAutosizer::getFingerprint(const RenderObject* renderer) +{ + Fingerprint result = m_fingerprintMapper.get(renderer); + if (!result) { + result = computeFingerprint(renderer); + m_fingerprintMapper.add(renderer, result); + } + return result; +} + +FastTextAutosizer::Fingerprint FastTextAutosizer::computeFingerprint(const RenderObject* renderer) +{ + Node* node = renderer->generatingNode(); + if (!node || !node->isElementNode()) + return 0; + + FingerprintSourceData data; + if (const RenderObject* parent = parentElementRenderer(renderer)) + data.m_parentHash = getFingerprint(parent); + + data.m_qualifiedNameHash = QualifiedNameHash::hash(toElement(node)->tagQName()); + + if (RenderStyle* style = renderer->style()) { + data.m_packedStyleProperties = style->direction(); + data.m_packedStyleProperties |= (style->position() << 1); + data.m_packedStyleProperties |= (style->floating() << 4); + data.m_packedStyleProperties |= (style->display() << 6); + data.m_packedStyleProperties |= (style->width().type() << 11); + // packedStyleProperties effectively using 15 bits now. + + // consider for adding: writing mode, padding. + + data.m_width = style->width().getFloatValue(); + } + + // Use nodeIndex as a rough approximation of column number + // (it's too early to call RenderTableCell::col). + // FIXME: account for colspan + if (renderer->isTableCell()) + data.m_column = renderer->node()->nodeIndex(); + + return StringHasher::computeHash<UChar>( + static_cast<const UChar*>(static_cast<const void*>(&data)), + sizeof data / sizeof(UChar)); +} + +FastTextAutosizer::Cluster* FastTextAutosizer::maybeCreateCluster(const RenderBlock* block) +{ + BlockFlags flags = classifyBlock(block); + if (!(flags & POTENTIAL_ROOT)) + return 0; + + Cluster* parentCluster = m_clusterStack.isEmpty() ? 0 : currentCluster(); + ASSERT(parentCluster || block->isRenderView()); + + // If a non-independent block would not alter the SUPPRESSING flag, it doesn't need to be a cluster. + bool parentSuppresses = parentCluster && (parentCluster->m_flags & SUPPRESSING); + if (!(flags & INDEPENDENT) && !(flags & EXPLICIT_WIDTH) && !!(flags & SUPPRESSING) == parentSuppresses) + return 0; + + Cluster* cluster = new Cluster(block, flags, parentCluster, getSupercluster(block)); +#ifdef AUTOSIZING_DOM_DEBUG_INFO + // Non-SUPPRESSING clusters are annotated in clusterMultiplier. + if (flags & SUPPRESSING) + writeClusterDebugInfo(cluster); +#endif + return cluster; +} + +FastTextAutosizer::Supercluster* FastTextAutosizer::getSupercluster(const RenderBlock* block) +{ + Fingerprint fingerprint = m_fingerprintMapper.get(block); + if (!fingerprint) + return 0; + + BlockSet* roots = &m_fingerprintMapper.getTentativeClusterRoots(fingerprint); + if (!roots || roots->size() < 2 || !roots->contains(block)) + return 0; + + SuperclusterMap::AddResult addResult = m_superclusters.add(fingerprint, PassOwnPtr<Supercluster>()); + if (!addResult.isNewEntry) + return addResult.storedValue->value.get(); + + Supercluster* supercluster = new Supercluster(roots); + addResult.storedValue->value = adoptPtr(supercluster); + return supercluster; +} + +float FastTextAutosizer::clusterMultiplier(Cluster* cluster) +{ + if (cluster->m_multiplier) + return cluster->m_multiplier; + + // FIXME: why does isWiderOrNarrowerDescendant crash on independent clusters? + if (!(cluster->m_flags & INDEPENDENT) && isWiderOrNarrowerDescendant(cluster)) + cluster->m_flags |= WIDER_OR_NARROWER; + + if (cluster->m_flags & (INDEPENDENT | WIDER_OR_NARROWER)) { + if (cluster->m_supercluster) + cluster->m_multiplier = superclusterMultiplier(cluster); + else if (clusterHasEnoughTextToAutosize(cluster)) + cluster->m_multiplier = multiplierFromBlock(clusterWidthProvider(cluster->m_root)); + else + cluster->m_multiplier = 1.0f; + } else { + cluster->m_multiplier = cluster->m_parent ? clusterMultiplier(cluster->m_parent) : 1.0f; + } + +#ifdef AUTOSIZING_DOM_DEBUG_INFO + writeClusterDebugInfo(cluster); +#endif + + ASSERT(cluster->m_multiplier); + return cluster->m_multiplier; +} + +bool FastTextAutosizer::superclusterHasEnoughTextToAutosize(Supercluster* supercluster, const RenderBlock* widthProvider) +{ + if (supercluster->m_hasEnoughTextToAutosize != UnknownAmountOfText) + return supercluster->m_hasEnoughTextToAutosize == HasEnoughText; + + BlockSet::iterator end = supercluster->m_roots->end(); + for (BlockSet::iterator it = supercluster->m_roots->begin(); it != end; ++it) { + if (clusterWouldHaveEnoughTextToAutosize(*it, widthProvider)) { + supercluster->m_hasEnoughTextToAutosize = HasEnoughText; + return true; + } + } + supercluster->m_hasEnoughTextToAutosize = NotEnoughText; + return false; +} + +float FastTextAutosizer::superclusterMultiplier(Cluster* cluster) +{ + Supercluster* supercluster = cluster->m_supercluster; + if (!supercluster->m_multiplier) { + const RenderBlock* widthProvider = maxClusterWidthProvider(cluster->m_supercluster, cluster->m_root); + supercluster->m_multiplier = superclusterHasEnoughTextToAutosize(supercluster, widthProvider) + ? multiplierFromBlock(widthProvider) : 1.0f; + } + ASSERT(supercluster->m_multiplier); + return supercluster->m_multiplier; +} + +const RenderBlock* FastTextAutosizer::clusterWidthProvider(const RenderBlock* root) +{ + if (root->isTable() || root->isTableCell()) + return root; + + return deepestBlockContainingAllText(root); +} + +const RenderBlock* FastTextAutosizer::maxClusterWidthProvider(const Supercluster* supercluster, const RenderBlock* currentRoot) +{ + const RenderBlock* result = clusterWidthProvider(currentRoot); + float maxWidth = widthFromBlock(result); + + const BlockSet* roots = supercluster->m_roots; + for (BlockSet::iterator it = roots->begin(); it != roots->end(); ++it) { + const RenderBlock* widthProvider = clusterWidthProvider(*it); + if (widthProvider->needsLayout()) continue; + float width = widthFromBlock(widthProvider); + if (width > maxWidth) { + maxWidth = width; + result = widthProvider; + } + } + RELEASE_ASSERT(result); + return result; +} + +float FastTextAutosizer::widthFromBlock(const RenderBlock* block) +{ + RELEASE_ASSERT(block); + RELEASE_ASSERT(block->style()); + + if (!(block->isTable() || block->isTableCell() || block->isListItem())) + return block->contentLogicalWidth().toFloat(); + + if (!block->containingBlock()) + return 0; + + // Tables may be inflated before computing their preferred widths. Try several methods to + // obtain a width, and fall back on a containing block's width. + do { + float width; + Length specifiedWidth = block->isTableCell() + ? toRenderTableCell(block)->styleOrColLogicalWidth() : block->style()->logicalWidth(); + if (specifiedWidth.isFixed()) { + if ((width = specifiedWidth.value()) > 0) + return width; + } + if (specifiedWidth.isPercent()) { + if (float containerWidth = block->containingBlock()->contentLogicalWidth().toFloat()) { + if ((width = floatValueForLength(specifiedWidth, containerWidth)) > 0) + return width; + } + } + if ((width = block->contentLogicalWidth().toFloat()) > 0) + return width; + } while ((block = block->containingBlock())); + return 0; +} + +float FastTextAutosizer::multiplierFromBlock(const RenderBlock* block) +{ + // If block->needsLayout() is false, it does not need to be in m_blocksThatHaveBegunLayout. + // This can happen during layout of a positioned object if the cluster's DBCAT is deeper + // than the positioned object's containing block, and wasn't marked as needing layout. + ASSERT(m_blocksThatHaveBegunLayout.contains(block) || !block->needsLayout()); + + // Block width, in CSS pixels. + float blockWidth = widthFromBlock(block); + float multiplier = m_pageInfo.m_frameWidth ? min(blockWidth, static_cast<float>(m_pageInfo.m_layoutWidth)) / m_pageInfo.m_frameWidth : 1.0f; + + return max(m_pageInfo.m_baseMultiplier * multiplier, 1.0f); +} + +const RenderBlock* FastTextAutosizer::deepestBlockContainingAllText(Cluster* cluster) +{ + if (!cluster->m_deepestBlockContainingAllText) + cluster->m_deepestBlockContainingAllText = deepestBlockContainingAllText(cluster->m_root); + + return cluster->m_deepestBlockContainingAllText; +} + +// FIXME: Refactor this to look more like FastTextAutosizer::deepestCommonAncestor. This is copied +// from TextAutosizer::findDeepestBlockContainingAllText. +const RenderBlock* FastTextAutosizer::deepestBlockContainingAllText(const RenderBlock* root) +{ + size_t firstDepth = 0; + const RenderObject* firstTextLeaf = findTextLeaf(root, firstDepth, First); + if (!firstTextLeaf) + return root; + + size_t lastDepth = 0; + const RenderObject* lastTextLeaf = findTextLeaf(root, lastDepth, Last); + ASSERT(lastTextLeaf); + + // Equalize the depths if necessary. Only one of the while loops below will get executed. + const RenderObject* firstNode = firstTextLeaf; + const RenderObject* lastNode = lastTextLeaf; + while (firstDepth > lastDepth) { + firstNode = firstNode->parent(); + --firstDepth; + } + while (lastDepth > firstDepth) { + lastNode = lastNode->parent(); + --lastDepth; + } + + // Go up from both nodes until the parent is the same. Both pointers will point to the LCA then. + while (firstNode != lastNode) { + firstNode = firstNode->parent(); + lastNode = lastNode->parent(); + } + + if (firstNode->isRenderBlock()) + return toRenderBlock(firstNode); + + // containingBlock() should never leave the cluster, since it only skips ancestors when finding + // the container of position:absolute/fixed blocks, and those cannot exist between a cluster and + // its text node's lowest common ancestor as isAutosizingCluster would have made them into their + // own independent cluster. + const RenderBlock* containingBlock = firstNode->containingBlock(); + if (!containingBlock) + return root; + + ASSERT(containingBlock->isDescendantOf(root)); + return containingBlock; +} + +const RenderObject* FastTextAutosizer::findTextLeaf(const RenderObject* parent, size_t& depth, TextLeafSearch firstOrLast) +{ + // List items are treated as text due to the marker. + // The actual renderer for the marker (RenderListMarker) may not be in the tree yet since it is added during layout. + if (parent->isListItem()) + return parent; + + if (parent->isText()) + return parent; + + ++depth; + const RenderObject* child = (firstOrLast == First) ? parent->slowFirstChild() : parent->slowLastChild(); + while (child) { + // Note: At this point clusters may not have been created for these blocks so we cannot rely + // on m_clusters. Instead, we use a best-guess about whether the block will become a cluster. + if (!classifyBlock(child, INDEPENDENT)) { + if (const RenderObject* leaf = findTextLeaf(child, depth, firstOrLast)) + return leaf; + } + child = (firstOrLast == First) ? child->nextSibling() : child->previousSibling(); + } + --depth; + + return 0; +} + +void FastTextAutosizer::applyMultiplier(RenderObject* renderer, float multiplier, RelayoutBehavior relayoutBehavior) +{ + ASSERT(renderer && renderer->style()); + RenderStyle* currentStyle = renderer->style(); + if (currentStyle->textAutosizingMultiplier() == multiplier) + return; + + // We need to clone the render style to avoid breaking style sharing. + RefPtr<RenderStyle> style = RenderStyle::clone(currentStyle); + style->setTextAutosizingMultiplier(multiplier); + style->setUnique(); + + switch (relayoutBehavior) { + case AlreadyInLayout: + // Don't free currentStyle until the end of the layout pass. This allows other parts of the system + // to safely hold raw RenderStyle* pointers during layout, e.g. BreakingContext::m_currentStyle. + m_stylesRetainedDuringLayout.append(currentStyle); + + renderer->setStyleInternal(style.release()); + renderer->setNeedsLayoutAndFullPaintInvalidation(); + break; + + case LayoutNeeded: + renderer->setStyle(style.release()); + break; + } + + if (multiplier != 1) + m_pageInfo.m_hasAutosized = true; +} + +bool FastTextAutosizer::isWiderOrNarrowerDescendant(Cluster* cluster) +{ + // FIXME: Why do we return true when hasExplicitWidth returns false?? + if (!cluster->m_parent || !hasExplicitWidth(cluster->m_root)) + return true; + + const RenderBlock* parentDeepestBlockContainingAllText = deepestBlockContainingAllText(cluster->m_parent); + ASSERT(m_blocksThatHaveBegunLayout.contains(cluster->m_root)); + ASSERT(m_blocksThatHaveBegunLayout.contains(parentDeepestBlockContainingAllText)); + + float contentWidth = cluster->m_root->contentLogicalWidth().toFloat(); + float clusterTextWidth = parentDeepestBlockContainingAllText->contentLogicalWidth().toFloat(); + + // Clusters with a root that is wider than the deepestBlockContainingAllText of their parent + // autosize independently of their parent. + if (contentWidth > clusterTextWidth) + return true; - applyMultiplier(inlineObj, cluster->m_multiplier); + // Clusters with a root that is significantly narrower than the deepestBlockContainingAllText of + // their parent autosize independently of their parent. + static float narrowWidthDifference = 200; + if (clusterTextWidth - contentWidth > narrowWidthDifference) + return true; + + return false; +} + +FastTextAutosizer::Cluster* FastTextAutosizer::currentCluster() const +{ + ASSERT_WITH_SECURITY_IMPLICATION(!m_clusterStack.isEmpty()); + return m_clusterStack.last().get(); +} + +#ifndef NDEBUG +void FastTextAutosizer::FingerprintMapper::assertMapsAreConsistent() +{ + // For each fingerprint -> block mapping in m_blocksForFingerprint we should have an associated + // map from block -> fingerprint in m_fingerprints. + ReverseFingerprintMap::iterator end = m_blocksForFingerprint.end(); + for (ReverseFingerprintMap::iterator fingerprintIt = m_blocksForFingerprint.begin(); fingerprintIt != end; ++fingerprintIt) { + Fingerprint fingerprint = fingerprintIt->key; + BlockSet* blocks = fingerprintIt->value.get(); + for (BlockSet::iterator blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) { + const RenderBlock* block = (*blockIt); + ASSERT(m_fingerprints.get(block) == fingerprint); + } } } +#endif + +void FastTextAutosizer::FingerprintMapper::add(const RenderObject* renderer, Fingerprint fingerprint) +{ + remove(renderer); + + m_fingerprints.set(renderer, fingerprint); +#ifndef NDEBUG + assertMapsAreConsistent(); +#endif +} + +void FastTextAutosizer::FingerprintMapper::addTentativeClusterRoot(const RenderBlock* block, Fingerprint fingerprint) +{ + add(block, fingerprint); + + ReverseFingerprintMap::AddResult addResult = m_blocksForFingerprint.add(fingerprint, PassOwnPtr<BlockSet>()); + if (addResult.isNewEntry) + addResult.storedValue->value = adoptPtr(new BlockSet); + addResult.storedValue->value->add(block); +#ifndef NDEBUG + assertMapsAreConsistent(); +#endif +} + +bool FastTextAutosizer::FingerprintMapper::remove(const RenderObject* renderer) +{ + Fingerprint fingerprint = m_fingerprints.take(renderer); + if (!fingerprint || !renderer->isRenderBlock()) + return false; + + ReverseFingerprintMap::iterator blocksIter = m_blocksForFingerprint.find(fingerprint); + if (blocksIter == m_blocksForFingerprint.end()) + return false; + + BlockSet& blocks = *blocksIter->value; + blocks.remove(toRenderBlock(renderer)); + if (blocks.isEmpty()) + m_blocksForFingerprint.remove(blocksIter); +#ifndef NDEBUG + assertMapsAreConsistent(); +#endif + return true; +} -AtomicString FastTextAutosizer::fingerprint(const RenderBlock* block) +FastTextAutosizer::Fingerprint FastTextAutosizer::FingerprintMapper::get(const RenderObject* renderer) { - // FIXME(crbug.com/322340): Implement a better fingerprinting algorithm. - return String::number((unsigned long long) block); + return m_fingerprints.get(renderer); } -float FastTextAutosizer::computeMultiplier(const FastTextAutosizer::Cluster* cluster) +FastTextAutosizer::BlockSet& FastTextAutosizer::FingerprintMapper::getTentativeClusterRoots(Fingerprint fingerprint) { - const WTF::HashSet<const RenderBlock*>& blocks = cluster->m_blocks; + return *m_blocksForFingerprint.get(fingerprint); +} + +FastTextAutosizer::LayoutScope::LayoutScope(RenderBlock* block) + : m_textAutosizer(block->document().fastTextAutosizer()) + , m_block(block) +{ + if (!m_textAutosizer) + return; - bool shouldAutosize = false; - for (WTF::HashSet<const RenderBlock*>::iterator it = blocks.begin(); it != blocks.end(); ++it) - shouldAutosize |= TextAutosizer::containerShouldBeAutosized(*it); + if (m_textAutosizer->shouldHandleLayout()) + m_textAutosizer->beginLayout(m_block); + else + m_textAutosizer = 0; +} - if (!shouldAutosize) - return 1.0f; +FastTextAutosizer::LayoutScope::~LayoutScope() +{ + if (m_textAutosizer) + m_textAutosizer->endLayout(m_block); +} - // FIXME(crbug.com/322344): Implement multiplier computation. - return 1.5f; + +FastTextAutosizer::TableLayoutScope::TableLayoutScope(RenderTable* table) + : LayoutScope(table) +{ + if (m_textAutosizer) { + ASSERT(m_textAutosizer->shouldHandleLayout()); + m_textAutosizer->inflateAutoTable(table); + } +} + +FastTextAutosizer::DeferUpdatePageInfo::DeferUpdatePageInfo(Page* page) + : m_mainFrame(page->deprecatedLocalMainFrame()) +{ + if (FastTextAutosizer* textAutosizer = m_mainFrame->document()->fastTextAutosizer()) { + ASSERT(!textAutosizer->m_updatePageInfoDeferred); + textAutosizer->m_updatePageInfoDeferred = true; + } +} + +FastTextAutosizer::DeferUpdatePageInfo::~DeferUpdatePageInfo() +{ + if (FastTextAutosizer* textAutosizer = m_mainFrame->document()->fastTextAutosizer()) { + ASSERT(textAutosizer->m_updatePageInfoDeferred); + textAutosizer->m_updatePageInfoDeferred = false; + textAutosizer->updatePageInfoInAllFrames(); + } } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/FastTextAutosizer.h b/chromium/third_party/WebKit/Source/core/rendering/FastTextAutosizer.h index 16265fd899a..f3f5efb2eab 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/FastTextAutosizer.h +++ b/chromium/third_party/WebKit/Source/core/rendering/FastTextAutosizer.h @@ -31,17 +31,20 @@ #ifndef FastTextAutosizer_h #define FastTextAutosizer_h +#include "core/rendering/RenderObject.h" +#include "core/rendering/RenderTable.h" #include "wtf/HashMap.h" #include "wtf/HashSet.h" #include "wtf/Noncopyable.h" #include "wtf/OwnPtr.h" #include "wtf/PassOwnPtr.h" -#include "wtf/text/AtomicStringHash.h" namespace WebCore { class Document; class RenderBlock; +class RenderListItem; +class RenderListMarker; // Single-pass text autosizer (work in progress). Works in two stages: // (1) record information about page elements during style recalc @@ -52,38 +55,255 @@ class FastTextAutosizer FINAL { WTF_MAKE_NONCOPYABLE(FastTextAutosizer); public: - static PassOwnPtr<FastTextAutosizer> create(Document* document) + static PassOwnPtr<FastTextAutosizer> create(const Document* document) { return adoptPtr(new FastTextAutosizer(document)); } + void updatePageInfoInAllFrames(); + void updatePageInfo(); void record(const RenderBlock*); void destroy(const RenderBlock*); - void inflate(RenderBlock*); + void inflateListItem(RenderListItem*, RenderListMarker*); + + class LayoutScope { + public: + explicit LayoutScope(RenderBlock*); + ~LayoutScope(); + protected: + FastTextAutosizer* m_textAutosizer; + RenderBlock* m_block; + }; + + class TableLayoutScope : LayoutScope { + public: + explicit TableLayoutScope(RenderTable*); + }; + + class DeferUpdatePageInfo { + public: + explicit DeferUpdatePageInfo(Page*); + ~DeferUpdatePageInfo(); + private: + RefPtr<LocalFrame> m_mainFrame; + }; private: - // TODO: make a proper API for this class? + typedef HashSet<const RenderBlock*> BlockSet; + + enum HasEnoughTextToAutosize { + UnknownAmountOfText, + HasEnoughText, + NotEnoughText + }; + + enum RelayoutBehavior { + AlreadyInLayout, // The default; appropriate if we are already in layout. + LayoutNeeded // Use this if changing a multiplier outside of layout. + }; + + enum BeginLayoutBehavior { + StopLayout, + ContinueLayout + }; + + enum InflateBehavior { + ThisBlockOnly, + DescendToInnerBlocks + }; + + enum BlockFlag { + // A block that is evaluated for becoming a cluster root. + POTENTIAL_ROOT = 1 << 0, + // A cluster root that establishes an independent multiplier. + INDEPENDENT = 1 << 1, + // A cluster root with an explicit width. These are likely to be independent. + EXPLICIT_WIDTH = 1 << 2, + // A cluster that is wider or narrower than its parent. These also create an + // independent multiplier, but this state cannot be determined until layout. + WIDER_OR_NARROWER = 1 << 3, + // A cluster that suppresses autosizing. + SUPPRESSING = 1 << 4 + }; + + typedef unsigned BlockFlags; + + // A supercluster represents autosizing information about a set of two or + // more blocks that all have the same fingerprint. Clusters whose roots + // belong to a supercluster will share a common multiplier and + // text-length-based autosizing status. + struct Supercluster { + explicit Supercluster(const BlockSet* roots) + : m_roots(roots) + , m_hasEnoughTextToAutosize(UnknownAmountOfText) + , m_multiplier(0) + { + } + + const BlockSet* const m_roots; + HasEnoughTextToAutosize m_hasEnoughTextToAutosize; + float m_multiplier; + }; + struct Cluster { - explicit Cluster(AtomicString fingerprint) - : m_fingerprint(fingerprint) + explicit Cluster(const RenderBlock* root, BlockFlags flags, Cluster* parent, Supercluster* supercluster = 0) + : m_root(root) + , m_flags(flags) + , m_deepestBlockContainingAllText(0) + , m_parent(parent) , m_multiplier(0) + , m_hasEnoughTextToAutosize(UnknownAmountOfText) + , m_supercluster(supercluster) + , m_hasTableAncestor(root->isTableCell() || (m_parent && m_parent->m_hasTableAncestor)) { } - AtomicString m_fingerprint; - WTF::HashSet<const RenderBlock*> m_blocks; + const RenderBlock* const m_root; + BlockFlags m_flags; + // The deepest block containing all text is computed lazily (see: + // deepestBlockContainingAllText). A value of 0 indicates the value has not been computed yet. + const RenderBlock* m_deepestBlockContainingAllText; + Cluster* m_parent; + // The multiplier is computed lazily (see: clusterMultiplier) because it must be calculated + // after the lowest block containing all text has entered layout (the + // m_blocksThatHaveBegunLayout assertions cover this). Note: the multiplier is still + // calculated when m_autosize is false because child clusters may depend on this multiplier. float m_multiplier; + HasEnoughTextToAutosize m_hasEnoughTextToAutosize; + // A set of blocks that are similar to this block. + Supercluster* m_supercluster; + bool m_hasTableAncestor; + }; + + enum TextLeafSearch { + First, + Last + }; + + struct FingerprintSourceData { + FingerprintSourceData() + : m_parentHash(0) + , m_qualifiedNameHash(0) + , m_packedStyleProperties(0) + , m_column(0) + , m_width(0) + { + } + + unsigned m_parentHash; + unsigned m_qualifiedNameHash; + // Style specific selection of signals + unsigned m_packedStyleProperties; + unsigned m_column; + float m_width; + }; + // Ensures efficient hashing using StringHasher. + COMPILE_ASSERT(!(sizeof(FingerprintSourceData) % sizeof(UChar)), + Sizeof_FingerprintSourceData_must_be_multiple_of_UChar); + + typedef unsigned Fingerprint; + typedef HashMap<Fingerprint, OwnPtr<Supercluster> > SuperclusterMap; + typedef Vector<OwnPtr<Cluster> > ClusterStack; + + // Fingerprints are computed during style recalc, for (some subset of) + // blocks that will become cluster roots. + class FingerprintMapper { + public: + void add(const RenderObject*, Fingerprint); + void addTentativeClusterRoot(const RenderBlock*, Fingerprint); + // Returns true if any BlockSet was modified or freed by the removal. + bool remove(const RenderObject*); + Fingerprint get(const RenderObject*); + BlockSet& getTentativeClusterRoots(Fingerprint); + private: + typedef HashMap<const RenderObject*, Fingerprint> FingerprintMap; + typedef HashMap<Fingerprint, OwnPtr<BlockSet> > ReverseFingerprintMap; + + FingerprintMap m_fingerprints; + ReverseFingerprintMap m_blocksForFingerprint; +#ifndef NDEBUG + void assertMapsAreConsistent(); +#endif + }; + + struct PageInfo { + PageInfo() + : m_frameWidth(0) + , m_layoutWidth(0) + , m_baseMultiplier(0) + , m_pageNeedsAutosizing(false) + , m_hasAutosized(false) + , m_settingEnabled(false) + { + } + + int m_frameWidth; // LocalFrame width in density-independent pixels (DIPs). + int m_layoutWidth; // Layout width in CSS pixels. + float m_baseMultiplier; // Includes accessibility font scale factor and device scale adjustment. + bool m_pageNeedsAutosizing; + bool m_hasAutosized; + bool m_settingEnabled; }; - explicit FastTextAutosizer(Document*); + explicit FastTextAutosizer(const Document*); - AtomicString fingerprint(const RenderBlock*); - float computeMultiplier(const Cluster*); + void beginLayout(RenderBlock*); + void endLayout(RenderBlock*); + void inflateAutoTable(RenderTable*); + float inflate(RenderObject*, InflateBehavior = ThisBlockOnly, float multiplier = 0); + bool shouldHandleLayout() const; + void setAllTextNeedsLayout(); + void resetMultipliers(); + BeginLayoutBehavior prepareForLayout(const RenderBlock*); + void prepareClusterStack(const RenderObject*); + bool clusterHasEnoughTextToAutosize(Cluster*, const RenderBlock* widthProvider = 0); + bool superclusterHasEnoughTextToAutosize(Supercluster*, const RenderBlock* widthProvider = 0); + bool clusterWouldHaveEnoughTextToAutosize(const RenderBlock* root, const RenderBlock* widthProvider = 0); + Fingerprint getFingerprint(const RenderObject*); + Fingerprint computeFingerprint(const RenderObject*); + Cluster* maybeCreateCluster(const RenderBlock*); + Supercluster* getSupercluster(const RenderBlock*); + float clusterMultiplier(Cluster*); + float superclusterMultiplier(Cluster*); + // A cluster's width provider is typically the deepest block containing all text. + // There are exceptions, such as tables and table cells which use the table itself for width. + const RenderBlock* clusterWidthProvider(const RenderBlock*); + const RenderBlock* maxClusterWidthProvider(const Supercluster*, const RenderBlock* currentRoot); + // Typically this returns a block's computed width. In the case of tables layout, this + // width is not yet known so the fixed width is used if it's available, or the containing + // block's width otherwise. + float widthFromBlock(const RenderBlock*); + float multiplierFromBlock(const RenderBlock*); + void applyMultiplier(RenderObject*, float, RelayoutBehavior = AlreadyInLayout); + bool isWiderOrNarrowerDescendant(Cluster*); + Cluster* currentCluster() const; + const RenderBlock* deepestBlockContainingAllText(Cluster*); + const RenderBlock* deepestBlockContainingAllText(const RenderBlock*); + // Returns the first text leaf that is in the current cluster. We attempt to not include text + // from descendant clusters but because descendant clusters may not exist, this is only an approximation. + // The TraversalDirection controls whether we return the first or the last text leaf. + const RenderObject* findTextLeaf(const RenderObject*, size_t&, TextLeafSearch); + BlockFlags classifyBlock(const RenderObject*, BlockFlags mask = UINT_MAX); +#ifdef AUTOSIZING_DOM_DEBUG_INFO + void writeClusterDebugInfo(Cluster*); +#endif - Document* m_document; + const Document* m_document; + const RenderBlock* m_firstBlockToBeginLayout; +#ifndef NDEBUG + BlockSet m_blocksThatHaveBegunLayout; // Used to ensure we don't compute properties of a block before beginLayout() is called on it. +#endif - WTF::HashMap<const RenderBlock*, Cluster*> m_clusterForBlock; - WTF::HashMap<AtomicString, OwnPtr<Cluster> > m_clusterForFingerprint; + // Clusters are created and destroyed during layout. The map key is the + // cluster root. Clusters whose roots share the same fingerprint use the + // same multiplier. + SuperclusterMap m_superclusters; + ClusterStack m_clusterStack; + FingerprintMapper m_fingerprintMapper; + Vector<RefPtr<RenderStyle> > m_stylesRetainedDuringLayout; + // FIXME: All frames should share the same m_pageInfo instance. + PageInfo m_pageInfo; + bool m_updatePageInfoDeferred; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/FilterEffectRenderer.cpp b/chromium/third_party/WebKit/Source/core/rendering/FilterEffectRenderer.cpp index ff60e9b0d76..3774afb7ec5 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/FilterEffectRenderer.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/FilterEffectRenderer.cpp @@ -45,11 +45,6 @@ #include "platform/graphics/filters/FEComponentTransfer.h" #include "platform/graphics/filters/FEDropShadow.h" #include "platform/graphics/filters/FEGaussianBlur.h" -#include "platform/graphics/filters/custom/CustomFilterGlobalContext.h" -#include "platform/graphics/filters/custom/CustomFilterValidatedProgram.h" -#include "platform/graphics/filters/custom/FECustomFilter.h" -#include "platform/graphics/filters/custom/ValidatedCustomFilterOperation.h" -#include "platform/graphics/gpu/AcceleratedImageBufferSurface.h" #include "wtf/MathExtras.h" #include <algorithm> @@ -70,35 +65,11 @@ static inline void lastMatrixRow(Vector<float>& parameters) 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; -} - -static PassRefPtr<FECustomFilter> createCustomFilterEffect(Filter* filter, Document* document, ValidatedCustomFilterOperation* operation) -{ - if (!document) - return 0; - - CustomFilterGlobalContext* globalContext = document->renderView()->customFilterGlobalContext(); - globalContext->prepareContextIfNeeded(); - if (!globalContext->context()) - return 0; - - return FECustomFilter::create(filter, globalContext->context(), operation->validatedProgram(), operation->parameters(), - operation->meshRows(), operation->meshColumns(), operation->meshType()); -} - FilterEffectRenderer::FilterEffectRenderer() : Filter(AffineTransform()) , m_graphicsBufferAttached(false) , m_hasFilterThatMovesPixels(false) - , m_hasCustomShaderFilter(false) { - setFilterResolution(FloatSize(1, 1)); m_sourceGraphic = SourceGraphic::create(this); } @@ -113,14 +84,15 @@ GraphicsContext* FilterEffectRenderer::inputContext() bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& operations) { - m_hasCustomShaderFilter = false; m_hasFilterThatMovesPixels = operations.hasFilterThatMovesPixels(); // Inverse zoom the pre-zoomed CSS shorthand filters, so that they are in the same zoom as the unzoomed reference filters. const RenderStyle* style = renderer->style(); - // FIXME: The effects now contain high dpi information, but the software path doesn't (yet) scale its backing. - // When the proper dpi dependant backing size is allocated, we should remove deviceScaleFactor(...) here. +#ifdef BLINK_SCALE_FILTERS_AT_RECORD_TIME float invZoom = 1.0f / ((style ? style->effectiveZoom() : 1.0f) * deviceScaleFactor(renderer->frame())); +#else + float invZoom = style ? 1.0f / style->effectiveZoom() : 1.0f; +#endif RefPtr<FilterEffect> previousEffect = m_sourceGraphic; for (size_t i = 0; i < operations.operations().size(); ++i) { @@ -256,18 +228,6 @@ bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& effect = FEDropShadow::create(this, stdDeviation, stdDeviation, x, y, dropShadowOperation->color(), 1); break; } - case FilterOperation::CUSTOM: - // CUSTOM operations are always converted to VALIDATED_CUSTOM before getting here. - // The conversion happens in RenderLayer::computeFilterOperations. - ASSERT_NOT_REACHED(); - break; - case FilterOperation::VALIDATED_CUSTOM: { - Document* document = renderer ? &renderer->document() : 0; - effect = createCustomFilterEffect(this, document, toValidatedCustomFilterOperation(filterOperation)); - if (effect) - m_hasCustomShaderFilter = true; - break; - } default: break; } @@ -283,7 +243,7 @@ bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& } } - // We need to keep the old effects alive until this point, so that filters like FECustomFilter + // We need to keep the old effects alive until this point, so that SVG reference filters // can share cached resources across frames. m_lastEffect = previousEffect; @@ -294,9 +254,10 @@ bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& return true; } -bool FilterEffectRenderer::updateBackingStoreRect(const FloatRect& filterRect) +bool FilterEffectRenderer::updateBackingStoreRect(const FloatRect& floatFilterRect) { - if (!filterRect.isZero() && isFilterSizeValid(filterRect)) { + IntRect filterRect = enclosingIntRect(floatFilterRect); + if (!filterRect.isEmpty() && FilterEffect::isFilterSizeValid(filterRect)) { FloatRect currentSourceRect = sourceImageRect(); if (filterRect != currentSourceRect) { setSourceImageRect(filterRect); @@ -314,13 +275,7 @@ void FilterEffectRenderer::allocateBackingStoreIfNeeded() if (!m_graphicsBufferAttached) { IntSize logicalSize(m_sourceDrawingRegion.width(), m_sourceDrawingRegion.height()); if (!sourceImage() || sourceImage()->size() != logicalSize) { - OwnPtr<ImageBufferSurface> surface; - if (isAccelerated()) { - surface = adoptPtr(new AcceleratedImageBufferSurface(logicalSize)); - } - if (!surface || !surface->isValid()) { - surface = adoptPtr(new UnacceleratedImageBufferSurface(logicalSize)); - } + OwnPtr<ImageBufferSurface> surface = adoptPtr(new UnacceleratedImageBufferSurface(logicalSize)); setSourceImage(ImageBuffer::create(surface.release())); } m_graphicsBufferAttached = true; @@ -342,18 +297,11 @@ void FilterEffectRenderer::apply() LayoutRect FilterEffectRenderer::computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect) { - 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; - } // The result of this function is the area in the "filterBoxRect" that needs to be repainted, so that we fully cover the "dirtyRect". FloatRect rectForRepaint = dirtyRect; - rectForRepaint.move(-filterBoxRect.location().x(), -filterBoxRect.location().y()); float inf = std::numeric_limits<float>::infinity(); FloatRect clipRect = FloatRect(FloatPoint(-inf, -inf), FloatSize(inf, inf)); rectForRepaint = lastEffect()->getSourceRect(rectForRepaint, clipRect); - rectForRepaint.move(filterBoxRect.location().x(), filterBoxRect.location().y()); rectForRepaint.intersect(filterBoxRect); return LayoutRect(rectForRepaint); } @@ -364,8 +312,22 @@ bool FilterEffectRendererHelper::prepareFilterEffect(RenderLayer* renderLayer, c m_renderLayer = renderLayer; m_repaintRect = dirtyRect; + // Get the zoom factor to scale the filterSourceRect input + const RenderLayerModelObject* renderer = renderLayer->renderer(); + const RenderStyle* style = renderer ? renderer->style() : 0; + float zoom = style ? style->effectiveZoom() : 1.0f; + + // Prepare a transformation that brings the coordinates into the space + // filter coordinates are defined in. + AffineTransform absoluteTransform; + // FIXME: Should these really be upconverted to doubles and not rounded? crbug.com/350474 + absoluteTransform.translate(filterBoxRect.x().toDouble(), filterBoxRect.y().toDouble()); + absoluteTransform.scale(zoom, zoom); + FilterEffectRenderer* filter = renderLayer->filterRenderer(); - LayoutRect filterSourceRect = filter->computeSourceImageRectForDirtyRect(filterBoxRect, dirtyRect); + filter->setAbsoluteTransform(absoluteTransform); + + IntRect filterSourceRect = pixelSnappedIntRect(filter->computeSourceImageRectForDirtyRect(filterBoxRect, dirtyRect)); if (filterSourceRect.isEmpty()) { // The dirty rect is not in view, just bail out. @@ -373,16 +335,7 @@ bool FilterEffectRendererHelper::prepareFilterEffect(RenderLayer* renderLayer, c return false; } - // Get the zoom factor to scale the filterSourceRect input - const RenderLayerModelObject* renderer = renderLayer->renderer(); - const RenderStyle* style = renderer ? renderer->style() : 0; - float zoom = style ? style->effectiveZoom() : 1.0f; - - AffineTransform absoluteTransform; - absoluteTransform.translate(filterBoxRect.x(), filterBoxRect.y()); - filter->setAbsoluteTransform(absoluteTransform); - filter->setAbsoluteFilterRegion(AffineTransform().scale(zoom).mapRect(filterSourceRect)); - filter->setFilterRegion(absoluteTransform.inverse().mapRect(filterSourceRect)); + filter->setFilterRegion(filter->mapAbsoluteRectToLocalRect(filterSourceRect)); filter->lastEffect()->determineFilterPrimitiveSubregion(MapRectForward); bool hasUpdatedBackingStore = filter->updateBackingStoreRect(filterSourceRect); @@ -405,7 +358,7 @@ GraphicsContext* FilterEffectRendererHelper::beginFilterEffect(GraphicsContext* filter->allocateBackingStoreIfNeeded(); // Paint into the context that represents the SourceGraphic of the filter. GraphicsContext* sourceGraphicsContext = filter->inputContext(); - if (!sourceGraphicsContext || !isFilterSizeValid(filter->absoluteFilterRegion())) { + if (!sourceGraphicsContext || !FilterEffect::isFilterSizeValid(filter->absoluteFilterRegion())) { // Disable the filters and continue. m_haveFilterEffect = false; return oldContext; @@ -434,7 +387,7 @@ GraphicsContext* FilterEffectRendererHelper::applyFilterEffect() filter->apply(); // Get the filtered output and draw it in place. - m_savedGraphicsContext->drawImageBuffer(filter->output(), filter->outputRect(), CompositeSourceOver); + m_savedGraphicsContext->drawImageBuffer(filter->output(), filter->outputRect()); filter->clearIntermediateResults(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/FilterEffectRenderer.h b/chromium/third_party/WebKit/Source/core/rendering/FilterEffectRenderer.h index 54f67f0ae8b..70c6909897e 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/FilterEffectRenderer.h +++ b/chromium/third_party/WebKit/Source/core/rendering/FilterEffectRenderer.h @@ -30,7 +30,6 @@ #include "platform/geometry/FloatRect.h" #include "platform/geometry/IntRectExtent.h" #include "platform/geometry/LayoutRect.h" -#include "platform/graphics/GraphicsContext.h" #include "platform/graphics/ImageBuffer.h" #include "platform/graphics/filters/Filter.h" #include "platform/graphics/filters/FilterEffect.h" @@ -42,9 +41,6 @@ namespace WebCore { -class ShaderResource; -class CustomFilterProgram; -class Document; class GraphicsContext; class RenderLayer; class RenderObject; @@ -74,7 +70,7 @@ private: bool m_haveFilterEffect; }; -class FilterEffectRenderer : public Filter +class FilterEffectRenderer FINAL : public Filter { WTF_MAKE_FAST_ALLOCATED; public: @@ -83,12 +79,12 @@ public: return adoptRef(new FilterEffectRenderer()); } - void setSourceImageRect(const FloatRect& sourceImageRect) + void setSourceImageRect(const IntRect& sourceImageRect) { m_sourceDrawingRegion = sourceImageRect; m_graphicsBufferAttached = false; } - virtual FloatRect sourceImageRect() const { return m_sourceDrawingRegion; } + virtual IntRect sourceImageRect() const OVERRIDE { return m_sourceDrawingRegion; } GraphicsContext* inputContext(); ImageBuffer* output() const { return lastEffect()->asImageBuffer(); } @@ -104,7 +100,6 @@ public: bool hasFilterThatMovesPixels() const { return m_hasFilterThatMovesPixels; } LayoutRect computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect); - bool hasCustomShaderFilter() const { return m_hasCustomShaderFilter; } PassRefPtr<FilterEffect> lastEffect() const { return m_lastEffect; @@ -114,7 +109,7 @@ private: FilterEffectRenderer(); virtual ~FilterEffectRenderer(); - FloatRect m_sourceDrawingRegion; + IntRect m_sourceDrawingRegion; RefPtr<SourceGraphic> m_sourceGraphic; RefPtr<FilterEffect> m_lastEffect; @@ -123,7 +118,6 @@ private: bool m_graphicsBufferAttached; bool m_hasFilterThatMovesPixels; - bool m_hasCustomShaderFilter; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/FixedTableLayout.cpp b/chromium/third_party/WebKit/Source/core/rendering/FixedTableLayout.cpp index 83cc6cebe96..25e4b83ffd3 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/FixedTableLayout.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/FixedTableLayout.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 2002 Lars Knoll (knoll@kde.org) * (C) 2002 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -137,18 +137,13 @@ int FixedTableLayout::calcWidthArray() unsigned currentColumn = 0; - RenderObject* firstRow = section->firstChild(); - for (RenderObject* child = firstRow->firstChild(); child; child = child->nextSibling()) { - if (!child->isTableCell()) - continue; - - RenderTableCell* cell = toRenderTableCell(child); - + RenderTableRow* firstRow = section->firstRow(); + for (RenderTableCell* cell = firstRow->firstCell(); cell; cell = cell->nextCell()) { Length logicalWidth = cell->styleOrColLogicalWidth(); unsigned span = cell->colSpan(); int fixedBorderBoxLogicalWidth = 0; // FIXME: Support other length types. If the width is non-auto, it should probably just use - // RenderBox::computeLogicalWidthInRegionUsing to compute the width. + // RenderBox::computeLogicalWidthUsing to compute the width. if (logicalWidth.isFixed() && logicalWidth.isPositive()) { fixedBorderBoxLogicalWidth = cell->adjustBorderBoxLogicalWidthForBoxSizing(logicalWidth.value()); logicalWidth.setValue(fixedBorderBoxLogicalWidth); @@ -330,11 +325,8 @@ void FixedTableLayout::willChangeTableLayout() RenderTableRow* row = section->rowRendererAt(i); if (!row) continue; - for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) { - if (!cell->isTableCell()) - continue; + for (RenderTableCell* cell = row->firstCell(); cell; cell = cell->nextCell()) cell->setPreferredLogicalWidthsDirty(); - } } } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/FloatingObjects.cpp b/chromium/third_party/WebKit/Source/core/rendering/FloatingObjects.cpp index 152a3a329c6..d455f53c053 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/FloatingObjects.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/FloatingObjects.cpp @@ -93,7 +93,6 @@ PassOwnPtr<FloatingObject> FloatingObject::copyToNewContainer(LayoutSize offset, PassOwnPtr<FloatingObject> FloatingObject::unsafeClone() const { OwnPtr<FloatingObject> cloneObject = adoptPtr(new FloatingObject(renderer(), type(), m_frameRect, m_shouldPaint, m_isDescendant)); - cloneObject->m_originatingLine = m_originatingLine; cloneObject->m_paginationStrut = m_paginationStrut; cloneObject->m_isPlaced = m_isPlaced; return cloneObject.release(); @@ -113,16 +112,16 @@ public: { } + virtual ~ComputeFloatOffsetAdapter() { } + int lowValue() const { return m_lineTop; } int highValue() const { return m_lineBottom; } void collectIfNeeded(const IntervalType&); LayoutUnit offset() const { return m_offset; } - LayoutUnit shapeOffset() const; - LayoutUnit heightRemaining() const; -private: - bool updateOffsetIfNeeded(const FloatingObject*); +protected: + virtual bool updateOffsetIfNeeded(const FloatingObject*) = 0; const RenderBlockFlow* m_renderer; int m_lineTop; @@ -131,11 +130,39 @@ private: const FloatingObject* m_outermostFloat; }; +template <FloatingObject::Type FloatTypeValue> +class ComputeFloatOffsetForFloatLayoutAdapter : public ComputeFloatOffsetAdapter<FloatTypeValue> { +public: + ComputeFloatOffsetForFloatLayoutAdapter(const RenderBlockFlow* renderer, LayoutUnit lineTop, LayoutUnit lineBottom, LayoutUnit offset) + : ComputeFloatOffsetAdapter<FloatTypeValue>(renderer, lineTop, lineBottom, offset) + { + } + + virtual ~ComputeFloatOffsetForFloatLayoutAdapter() { } + + LayoutUnit heightRemaining() const; + +protected: + virtual bool updateOffsetIfNeeded(const FloatingObject*) OVERRIDE FINAL; +}; + +template <FloatingObject::Type FloatTypeValue> +class ComputeFloatOffsetForLineLayoutAdapter : public ComputeFloatOffsetAdapter<FloatTypeValue> { +public: + ComputeFloatOffsetForLineLayoutAdapter(const RenderBlockFlow* renderer, LayoutUnit lineTop, LayoutUnit lineBottom, LayoutUnit offset) + : ComputeFloatOffsetAdapter<FloatTypeValue>(renderer, lineTop, lineBottom, offset) + { + } + + virtual ~ComputeFloatOffsetForLineLayoutAdapter() { } + +protected: + virtual bool updateOffsetIfNeeded(const FloatingObject*) OVERRIDE FINAL; +}; + FloatingObjects::~FloatingObjects() { - // FIXME: m_set should use OwnPtr instead. - deleteAllValues(m_set); } void FloatingObjects::clearLineBoxTreePointers() { @@ -147,17 +174,6 @@ void FloatingObjects::clearLineBoxTreePointers() } } -template<> -inline bool ComputeFloatOffsetAdapter<FloatingObject::FloatLeft>::updateOffsetIfNeeded(const FloatingObject* floatingObject) -{ - LayoutUnit logicalRight = m_renderer->logicalRightForFloat(floatingObject); - if (logicalRight > m_offset) { - m_offset = logicalRight; - return true; - } - return false; -} - FloatingObjects::FloatingObjects(const RenderBlockFlow* renderer, bool horizontalWritingMode) : m_placedFloatsTree(UninitializedTree) , m_leftObjectsCount(0) @@ -170,7 +186,6 @@ FloatingObjects::FloatingObjects(const RenderBlockFlow* renderer, bool horizonta void FloatingObjects::clear() { - deleteAllValues(m_set); m_set.clear(); m_placedFloatsTree.clear(); m_leftObjectsCount = 0; @@ -198,7 +213,7 @@ LayoutUnit FloatingObjects::lowestFloatLogicalBottom(FloatingObject::Type floatT LayoutUnit lowestFloatBottomLeft = 0; LayoutUnit lowestFloatBottomRight = 0; for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); if (floatingObject->isPlaced()) { FloatingObject::Type curType = floatingObject->type(); LayoutUnit curFloatLogicalBottom = m_renderer->logicalBottomForFloat(floatingObject); @@ -213,7 +228,7 @@ LayoutUnit FloatingObjects::lowestFloatLogicalBottom(FloatingObject::Type floatT setCachedLowestFloatLogicalBottom(isInHorizontalWritingMode, FloatingObject::FloatRight, lowestFloatBottomRight); } else { for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); if (floatingObject->isPlaced() && floatingObject->type() == floatType) lowestFloatBottom = max(lowestFloatBottom, m_renderer->logicalBottomForFloat(floatingObject)); } @@ -257,13 +272,11 @@ void FloatingObjects::markLowestFloatLogicalBottomCacheAsDirty() void FloatingObjects::moveAllToFloatInfoMap(RendererToFloatInfoMap& map) { - FloatingObjectSetIterator end = m_set.end(); - for (FloatingObjectSetIterator it = m_set.begin(); it != end; ++it) - map.add((*it)->renderer(), *it); - - // clear set before clearing this because we don't want to delete all of - // the objects we have just transferred. - m_set.clear(); + while (!m_set.isEmpty()) { + OwnPtr<FloatingObject> floatingObject = m_set.takeFirst(); + RenderBox* renderer = floatingObject->renderer(); + map.add(renderer, floatingObject.release()); + } clear(); } @@ -324,23 +337,22 @@ FloatingObject* FloatingObjects::add(PassOwnPtr<FloatingObject> floatingObject) { FloatingObject* newObject = floatingObject.leakPtr(); increaseObjectsCount(newObject->type()); - m_set.add(newObject); + m_set.add(adoptPtr(newObject)); if (newObject->isPlaced()) addPlacedObject(newObject); markLowestFloatLogicalBottomCacheAsDirty(); return newObject; } -void FloatingObjects::remove(FloatingObject* floatingObject) +void FloatingObjects::remove(FloatingObject* toBeRemoved) { - decreaseObjectsCount(floatingObject->type()); - m_set.remove(floatingObject); + decreaseObjectsCount(toBeRemoved->type()); + OwnPtr<FloatingObject> floatingObject = m_set.take(toBeRemoved); ASSERT(floatingObject->isPlaced() || !floatingObject->isInPlacedTree()); if (floatingObject->isPlaced()) - removePlacedObject(floatingObject); + removePlacedObject(floatingObject.get()); markLowestFloatLogicalBottomCacheAsDirty(); ASSERT(!floatingObject->originatingLine()); - delete floatingObject; } void FloatingObjects::computePlacedFloatsTree() @@ -352,46 +364,16 @@ void FloatingObjects::computePlacedFloatsTree() FloatingObjectSetIterator it = m_set.begin(); FloatingObjectSetIterator end = m_set.end(); for (; it != end; ++it) { - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); if (floatingObject->isPlaced()) m_placedFloatsTree.add(intervalForFloatingObject(floatingObject)); } } -static inline ShapeOutsideInfo* shapeInfoForFloat(const FloatingObject* floatingObject, const RenderBlockFlow* containingBlock, LayoutUnit lineTop, LayoutUnit lineBottom) -{ - if (floatingObject) { - if (ShapeOutsideInfo* shapeOutside = floatingObject->renderer()->shapeOutsideInfo()) { - shapeOutside->updateDeltasForContainingBlockLine(containingBlock, floatingObject, lineTop, lineBottom - lineTop); - return shapeOutside; - } - } - - return 0; -} - -template<> -inline LayoutUnit ComputeFloatOffsetAdapter<FloatingObject::FloatLeft>::shapeOffset() const -{ - if (ShapeOutsideInfo* shapeOutside = shapeInfoForFloat(m_outermostFloat, m_renderer, m_lineTop, m_lineBottom)) - return m_offset + shapeOutside->rightMarginBoxDelta(); - - return m_offset; -} - -template<> -inline LayoutUnit ComputeFloatOffsetAdapter<FloatingObject::FloatRight>::shapeOffset() const -{ - if (ShapeOutsideInfo* shapeOutside = shapeInfoForFloat(m_outermostFloat, m_renderer, m_lineTop, m_lineBottom)) - return m_offset + shapeOutside->leftMarginBoxDelta(); - - return m_offset; -} - LayoutUnit FloatingObjects::logicalLeftOffsetForPositioningFloat(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit *heightRemaining) { int logicalTopAsInt = roundToInt(logicalTop); - ComputeFloatOffsetAdapter<FloatingObject::FloatLeft> adapter(m_renderer, logicalTopAsInt, logicalTopAsInt, fixedOffset); + ComputeFloatOffsetForFloatLayoutAdapter<FloatingObject::FloatLeft> adapter(m_renderer, logicalTopAsInt, logicalTopAsInt, fixedOffset); placedFloatsTree().allOverlapsWithAdapter(adapter); if (heightRemaining) @@ -403,7 +385,7 @@ LayoutUnit FloatingObjects::logicalLeftOffsetForPositioningFloat(LayoutUnit fixe LayoutUnit FloatingObjects::logicalRightOffsetForPositioningFloat(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit *heightRemaining) { int logicalTopAsInt = roundToInt(logicalTop); - ComputeFloatOffsetAdapter<FloatingObject::FloatRight> adapter(m_renderer, logicalTopAsInt, logicalTopAsInt, fixedOffset); + ComputeFloatOffsetForFloatLayoutAdapter<FloatingObject::FloatRight> adapter(m_renderer, logicalTopAsInt, logicalTopAsInt, fixedOffset); placedFloatsTree().allOverlapsWithAdapter(adapter); if (heightRemaining) @@ -414,18 +396,18 @@ LayoutUnit FloatingObjects::logicalRightOffsetForPositioningFloat(LayoutUnit fix LayoutUnit FloatingObjects::logicalLeftOffset(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit logicalHeight) { - ComputeFloatOffsetAdapter<FloatingObject::FloatLeft> adapter(m_renderer, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), fixedOffset); + ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::FloatLeft> adapter(m_renderer, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), fixedOffset); placedFloatsTree().allOverlapsWithAdapter(adapter); - return adapter.shapeOffset(); + return adapter.offset(); } LayoutUnit FloatingObjects::logicalRightOffset(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit logicalHeight) { - ComputeFloatOffsetAdapter<FloatingObject::FloatRight> adapter(m_renderer, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), fixedOffset); + ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::FloatRight> adapter(m_renderer, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), fixedOffset); placedFloatsTree().allOverlapsWithAdapter(adapter); - return min(fixedOffset, adapter.shapeOffset()); + return min(fixedOffset, adapter.offset()); } FloatingObjects::FloatBottomCachedValue::FloatBottomCachedValue() @@ -455,7 +437,18 @@ inline static bool rangesIntersect(int floatTop, int floatBottom, int objectTop, } template<> -inline bool ComputeFloatOffsetAdapter<FloatingObject::FloatRight>::updateOffsetIfNeeded(const FloatingObject* floatingObject) +inline bool ComputeFloatOffsetForFloatLayoutAdapter<FloatingObject::FloatLeft>::updateOffsetIfNeeded(const FloatingObject* floatingObject) +{ + LayoutUnit logicalRight = m_renderer->logicalRightForFloat(floatingObject); + if (logicalRight > m_offset) { + m_offset = logicalRight; + return true; + } + return false; +} + +template<> +inline bool ComputeFloatOffsetForFloatLayoutAdapter<FloatingObject::FloatRight>::updateOffsetIfNeeded(const FloatingObject* floatingObject) { LayoutUnit logicalLeft = m_renderer->logicalLeftForFloat(floatingObject); if (logicalLeft < m_offset) { @@ -466,6 +459,12 @@ inline bool ComputeFloatOffsetAdapter<FloatingObject::FloatRight>::updateOffsetI } template <FloatingObject::Type FloatTypeValue> +LayoutUnit ComputeFloatOffsetForFloatLayoutAdapter<FloatTypeValue>::heightRemaining() const +{ + return this->m_outermostFloat ? this->m_renderer->logicalBottomForFloat(this->m_outermostFloat) - this->m_lineTop : LayoutUnit(1); +} + +template <FloatingObject::Type FloatTypeValue> inline void ComputeFloatOffsetAdapter<FloatTypeValue>::collectIfNeeded(const IntervalType& interval) { const FloatingObject* floatingObject = interval.data(); @@ -482,10 +481,52 @@ inline void ComputeFloatOffsetAdapter<FloatTypeValue>::collectIfNeeded(const Int m_outermostFloat = floatingObject; } -template <FloatingObject::Type FloatTypeValue> -LayoutUnit ComputeFloatOffsetAdapter<FloatTypeValue>::heightRemaining() const +static inline ShapeOutsideInfo* shapeInfoForFloat(const FloatingObject& floatingObject, const RenderBlockFlow& containingBlock, LayoutUnit lineTop, LayoutUnit lineBottom) +{ + if (ShapeOutsideInfo* shapeOutside = floatingObject.renderer()->shapeOutsideInfo()) { + shapeOutside->updateDeltasForContainingBlockLine(containingBlock, floatingObject, lineTop, lineBottom - lineTop); + return shapeOutside; + } + + return 0; +} + +template<> +inline bool ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::FloatLeft>::updateOffsetIfNeeded(const FloatingObject* floatingObject) +{ + ASSERT(floatingObject); + LayoutUnit logicalRight = m_renderer->logicalRightForFloat(floatingObject); + if (ShapeOutsideInfo* shapeOutside = shapeInfoForFloat(*floatingObject, *m_renderer, m_lineTop, m_lineBottom)) { + if (!shapeOutside->lineOverlapsShape()) + return false; + + logicalRight += shapeOutside->rightMarginBoxDelta(); + } + if (logicalRight > m_offset) { + m_offset = logicalRight; + return true; + } + + return false; +} + +template<> +inline bool ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::FloatRight>::updateOffsetIfNeeded(const FloatingObject* floatingObject) { - return m_outermostFloat ? m_renderer->logicalBottomForFloat(m_outermostFloat) - m_lineTop : LayoutUnit(1); + ASSERT(floatingObject); + LayoutUnit logicalLeft = m_renderer->logicalLeftForFloat(floatingObject); + if (ShapeOutsideInfo* shapeOutside = shapeInfoForFloat(*floatingObject, *m_renderer, m_lineTop, m_lineBottom)) { + if (!shapeOutside->lineOverlapsShape()) + return false; + + logicalLeft += shapeOutside->leftMarginBoxDelta(); + } + if (logicalLeft < m_offset) { + m_offset = logicalLeft; + return true; + } + + return false; } #ifndef NDEBUG diff --git a/chromium/third_party/WebKit/Source/core/rendering/FloatingObjects.h b/chromium/third_party/WebKit/Source/core/rendering/FloatingObjects.h index ca3beb1a345..f7062249639 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/FloatingObjects.h +++ b/chromium/third_party/WebKit/Source/core/rendering/FloatingObjects.h @@ -113,19 +113,25 @@ private: struct FloatingObjectHashFunctions { static unsigned hash(FloatingObject* key) { return DefaultHash<RenderBox*>::Hash::hash(key->renderer()); } - static bool equal(FloatingObject* a, FloatingObject* b) { return a->renderer() == b->renderer(); } + static unsigned hash(const OwnPtr<FloatingObject>& key) { return hash(key.get()); } + static unsigned hash(const PassOwnPtr<FloatingObject>& key) { return hash(key.get()); } + static bool equal(OwnPtr<FloatingObject>& a, FloatingObject* b) { return a->renderer() == b->renderer(); } + static bool equal(OwnPtr<FloatingObject>& a, const OwnPtr<FloatingObject>& b) { return equal(a, b.get()); } + static bool equal(OwnPtr<FloatingObject>& a, const PassOwnPtr<FloatingObject>& b) { return equal(a, b.get()); } + static const bool safeToCompareToEmptyOrDeleted = true; }; struct FloatingObjectHashTranslator { static unsigned hash(RenderBox* key) { return DefaultHash<RenderBox*>::Hash::hash(key); } static bool equal(FloatingObject* a, RenderBox* b) { return a->renderer() == b; } + static bool equal(const OwnPtr<WebCore::FloatingObject>& a, RenderBox* b) { return a->renderer() == b; } }; -typedef ListHashSet<FloatingObject*, 4, FloatingObjectHashFunctions> FloatingObjectSet; +typedef ListHashSet<OwnPtr<FloatingObject>, 4, FloatingObjectHashFunctions> FloatingObjectSet; typedef FloatingObjectSet::const_iterator FloatingObjectSetIterator; typedef PODInterval<int, FloatingObject*> FloatingObjectInterval; typedef PODIntervalTree<int, FloatingObject*> FloatingObjectTree; typedef PODFreeListArena<PODRedBlackTree<FloatingObjectInterval>::Node> IntervalArena; -typedef HashMap<RenderBox*, FloatingObject*> RendererToFloatInfoMap; +typedef HashMap<RenderBox*, OwnPtr<FloatingObject> > RendererToFloatInfoMap; class FloatingObjects { WTF_MAKE_NONCOPYABLE(FloatingObjects); WTF_MAKE_FAST_ALLOCATED; diff --git a/chromium/third_party/WebKit/Source/core/rendering/FlowThreadController.cpp b/chromium/third_party/WebKit/Source/core/rendering/FlowThreadController.cpp index 521085ee453..59e5cf1cbf6 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/FlowThreadController.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/FlowThreadController.cpp @@ -31,218 +31,16 @@ #include "core/rendering/FlowThreadController.h" -#include "core/dom/NamedFlowCollection.h" -#include "core/rendering/RenderFlowThread.h" -#include "core/rendering/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) - , m_flowThreadsWithAutoLogicalHeightRegions(0) -{ -} - -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; - } - } - - NamedFlowCollection* namedFlows = m_view->document().namedFlows(); - - // Sanity check for the absence of a named flow in the "CREATED" state with the same name. - ASSERT(!namedFlows->flowByName(name)); - - RenderNamedFlowThread* flowRenderer = RenderNamedFlowThread::createAnonymous(&m_view->document(), namedFlows->ensureFlowWithName(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::styleDidChange() +PassOwnPtr<FlowThreadController> FlowThreadController::create() { - RenderStyle* viewStyle = m_view->style(); - for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) { - RenderNamedFlowThread* flowRenderer = *iter; - flowRenderer->setStyle(RenderFlowThread::createFlowThreadStyle(viewStyle)); - } -} - -void FlowThreadController::layoutRenderNamedFlowThreads() -{ - updateFlowThreadsChainIfNecessary(); - - for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) { - RenderNamedFlowThread* flowRenderer = *iter; - flowRenderer->layoutIfNeeded(); - } + return adoptPtr(new FlowThreadController); } -void FlowThreadController::registerNamedFlowContentNode(Node* contentNode, RenderNamedFlowThread* namedFlow) +FlowThreadController::FlowThreadController() + : m_currentRenderFlowThread(0) { - 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<const Node*, RenderNamedFlowThread*>::iterator it = m_mapNamedFlowContentNodes.find(contentNode); - ASSERT_WITH_SECURITY_IMPLICATION(it != m_mapNamedFlowContentNodes.end()); - ASSERT(it->value); - ASSERT(it->value->hasContentNode(contentNode)); - it->value->unregisterNamedFlowContentNode(contentNode); - m_mapNamedFlowContentNodes.remove(contentNode); -} - -void FlowThreadController::updateFlowThreadsChainIfNecessary() -{ - ASSERT(m_renderNamedFlowThreadList); - ASSERT(isAutoLogicalHeightRegionsCountConsistent()); - - // Remove the left-over flow threads. - RenderNamedFlowThreadList toRemoveList; - for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) { - RenderNamedFlowThread* flowRenderer = *iter; - if (flowRenderer->isMarkedForDestruction()) - toRemoveList.add(flowRenderer); - } - - if (toRemoveList.size() > 0) - setIsRenderNamedFlowThreadOrderDirty(true); - - for (RenderNamedFlowThreadList::iterator iter = toRemoveList.begin(); iter != toRemoveList.end(); ++iter) { - RenderNamedFlowThread* flowRenderer = *iter; - m_renderNamedFlowThreadList->remove(flowRenderer); - flowRenderer->destroy(); - } - - 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); - } -} - -bool FlowThreadController::updateFlowThreadsNeedingLayout() -{ - bool needsTwoPassLayout = false; - - for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) { - RenderNamedFlowThread* flowRenderer = *iter; - ASSERT(!flowRenderer->needsTwoPhasesLayout()); - flowRenderer->setInConstrainedLayoutPhase(false); - if (flowRenderer->needsLayout() && flowRenderer->hasAutoLogicalHeightRegions()) - needsTwoPassLayout = true; - } - - if (needsTwoPassLayout) - resetFlowThreadsWithAutoHeightRegions(); - - return needsTwoPassLayout; -} - -bool FlowThreadController::updateFlowThreadsNeedingTwoStepLayout() -{ - bool needsTwoPassLayout = false; - - for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) { - RenderNamedFlowThread* flowRenderer = *iter; - if (flowRenderer->needsTwoPhasesLayout()) { - needsTwoPassLayout = true; - break; - } - } - - if (needsTwoPassLayout) - resetFlowThreadsWithAutoHeightRegions(); - - return needsTwoPassLayout; -} - -void FlowThreadController::resetFlowThreadsWithAutoHeightRegions() -{ - for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) { - RenderNamedFlowThread* flowRenderer = *iter; - if (flowRenderer->hasAutoLogicalHeightRegions()) { - flowRenderer->markAutoLogicalHeightRegionsForLayout(); - flowRenderer->invalidateRegions(); - } - } -} - -void FlowThreadController::updateFlowThreadsIntoConstrainedPhase() -{ - // Walk the flow chain in reverse order to update the auto-height regions and compute correct sizes for the containing regions. Only after this we can - // set the flow in the constrained layout phase. - for (RenderNamedFlowThreadList::reverse_iterator iter = m_renderNamedFlowThreadList->rbegin(); iter != m_renderNamedFlowThreadList->rend(); ++iter) { - RenderNamedFlowThread* flowRenderer = *iter; - ASSERT(!flowRenderer->hasRegions() || flowRenderer->hasValidRegionInfo()); - flowRenderer->layoutIfNeeded(); - if (flowRenderer->hasAutoLogicalHeightRegions()) { - ASSERT(flowRenderer->needsTwoPhasesLayout()); - flowRenderer->markAutoLogicalHeightRegionsForLayout(); - } - flowRenderer->setInConstrainedLayoutPhase(true); - flowRenderer->clearNeedsTwoPhasesLayout(); - } -} - -bool FlowThreadController::isContentNodeRegisteredWithAnyNamedFlow(const Node* contentNode) const -{ - return m_mapNamedFlowContentNodes.contains(contentNode); -} - -#ifndef NDEBUG -bool FlowThreadController::isAutoLogicalHeightRegionsCountConsistent() const -{ - if (!hasRenderNamedFlowThreads()) - return !hasFlowThreadsWithAutoLogicalHeightRegions(); - - for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) { - if (!(*iter)->isAutoLogicalHeightRegionsCountConsistent()) - return false; - } - - return true; } -#endif } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/FlowThreadController.h b/chromium/third_party/WebKit/Source/core/rendering/FlowThreadController.h index 7f56615d7de..1b1372b29b1 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/FlowThreadController.h +++ b/chromium/third_party/WebKit/Source/core/rendering/FlowThreadController.h @@ -30,69 +30,26 @@ #ifndef FlowThreadController_h #define FlowThreadController_h -#include "core/rendering/RenderView.h" -#include "wtf/ListHashSet.h" -#include "wtf/OwnPtr.h" +#include "wtf/FastAllocBase.h" +#include "wtf/PassOwnPtr.h" namespace WebCore { class RenderFlowThread; -class RenderNamedFlowThread; - -typedef ListHashSet<RenderNamedFlowThread*> RenderNamedFlowThreadList; class FlowThreadController { WTF_MAKE_FAST_ALLOCATED; public: - static PassOwnPtr<FlowThreadController> create(RenderView*); - ~FlowThreadController(); + static PassOwnPtr<FlowThreadController> create(); 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(); - } - - RenderNamedFlowThread* ensureRenderFlowThreadWithName(const AtomicString&); - const RenderNamedFlowThreadList* renderNamedFlowThreadList() const { return m_renderNamedFlowThreadList.get(); } - bool hasRenderNamedFlowThreads() const { return m_renderNamedFlowThreadList && !m_renderNamedFlowThreadList->isEmpty(); } - void layoutRenderNamedFlowThreads(); - void styleDidChange(); - - void registerNamedFlowContentNode(Node*, RenderNamedFlowThread*); - void unregisterNamedFlowContentNode(Node*); - bool isContentNodeRegisteredWithAnyNamedFlow(const Node*) const; - - bool hasFlowThreadsWithAutoLogicalHeightRegions() const { return m_flowThreadsWithAutoLogicalHeightRegions; } - void incrementFlowThreadsWithAutoLogicalHeightRegions() { ++m_flowThreadsWithAutoLogicalHeightRegions; } - void decrementFlowThreadsWithAutoLogicalHeightRegions() { ASSERT(m_flowThreadsWithAutoLogicalHeightRegions > 0); --m_flowThreadsWithAutoLogicalHeightRegions; } - - bool updateFlowThreadsNeedingLayout(); - bool updateFlowThreadsNeedingTwoStepLayout(); - void updateFlowThreadsIntoConstrainedPhase(); - -#ifndef NDEBUG - bool isAutoLogicalHeightRegionsCountConsistent() const; -#endif - protected: - FlowThreadController(RenderView*); - void updateFlowThreadsChainIfNecessary(); - void resetFlowThreadsWithAutoHeightRegions(); + FlowThreadController(); private: - RenderView* m_view; RenderFlowThread* m_currentRenderFlowThread; - bool m_isRenderNamedFlowThreadOrderDirty; - unsigned m_flowThreadsWithAutoLogicalHeightRegions; - OwnPtr<RenderNamedFlowThreadList> m_renderNamedFlowThreadList; - // maps a content node to its render flow thread. - HashMap<const Node*, RenderNamedFlowThread*> m_mapNamedFlowContentNodes; }; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/HitTestLocation.cpp b/chromium/third_party/WebKit/Source/core/rendering/HitTestLocation.cpp index f532480df20..20d4ba557e9 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/HitTestLocation.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/HitTestLocation.cpp @@ -22,17 +22,10 @@ #include "config.h" #include "core/rendering/HitTestLocation.h" -#include "HTMLNames.h" -#include "SVGNames.h" -#include "XLinkNames.h" - namespace WebCore { -using namespace HTMLNames; - HitTestLocation::HitTestLocation() - : m_region(0) - , m_isRectBased(false) + : m_isRectBased(false) , m_isRectilinear(true) { } @@ -42,7 +35,6 @@ HitTestLocation::HitTestLocation(const LayoutPoint& point) , m_boundingBox(rectForPoint(point, 0, 0, 0, 0)) , m_transformedPoint(point) , m_transformedRect(m_boundingBox) - , m_region(0) , m_isRectBased(false) , m_isRectilinear(true) { @@ -53,7 +45,6 @@ HitTestLocation::HitTestLocation(const FloatPoint& point) , m_boundingBox(rectForPoint(m_point, 0, 0, 0, 0)) , m_transformedPoint(point) , m_transformedRect(m_boundingBox) - , m_region(0) , m_isRectBased(false) , m_isRectilinear(true) { @@ -62,7 +53,6 @@ HitTestLocation::HitTestLocation(const FloatPoint& point) HitTestLocation::HitTestLocation(const FloatPoint& point, const FloatQuad& quad) : m_transformedPoint(point) , m_transformedRect(quad) - , m_region(0) , m_isRectBased(true) { m_point = flooredLayoutPoint(point); @@ -74,19 +64,17 @@ HitTestLocation::HitTestLocation(const LayoutPoint& centerPoint, unsigned topPad : m_point(centerPoint) , m_boundingBox(rectForPoint(centerPoint, topPadding, rightPadding, bottomPadding, leftPadding)) , m_transformedPoint(centerPoint) - , m_region(0) , m_isRectBased(topPadding || rightPadding || bottomPadding || leftPadding) , m_isRectilinear(true) { m_transformedRect = FloatQuad(m_boundingBox); } -HitTestLocation::HitTestLocation(const HitTestLocation& other, const LayoutSize& offset, RenderRegion* region) +HitTestLocation::HitTestLocation(const HitTestLocation& other, const LayoutSize& offset) : m_point(other.m_point) , m_boundingBox(other.m_boundingBox) , m_transformedPoint(other.m_transformedPoint) , m_transformedRect(other.m_transformedRect) - , m_region(region ? region : other.m_region) , m_isRectBased(other.m_isRectBased) , m_isRectilinear(other.m_isRectilinear) { @@ -98,7 +86,6 @@ HitTestLocation::HitTestLocation(const HitTestLocation& other) , m_boundingBox(other.m_boundingBox) , m_transformedPoint(other.m_transformedPoint) , m_transformedRect(other.m_transformedRect) - , m_region(other.m_region) , m_isRectBased(other.m_isRectBased) , m_isRectilinear(other.m_isRectilinear) { @@ -114,7 +101,6 @@ HitTestLocation& HitTestLocation::operator=(const HitTestLocation& other) m_boundingBox = other.m_boundingBox; m_transformedPoint = other.m_transformedPoint; m_transformedRect = other.m_transformedRect; - m_region = other.m_region; m_isRectBased = other.m_isRectBased; m_isRectilinear = other.m_isRectilinear; diff --git a/chromium/third_party/WebKit/Source/core/rendering/HitTestLocation.h b/chromium/third_party/WebKit/Source/core/rendering/HitTestLocation.h index 7edcd8e03bc..ff18d79c646 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/HitTestLocation.h +++ b/chromium/third_party/WebKit/Source/core/rendering/HitTestLocation.h @@ -33,14 +33,6 @@ namespace WebCore { -class Element; -class Frame; -class Image; -class KURL; -class Node; -class RenderRegion; -class Scrollbar; - class HitTestLocation { public: @@ -50,8 +42,7 @@ public: HitTestLocation(const FloatPoint&, const FloatQuad&); // Pass non-zero padding values to perform a rect-based hit test. HitTestLocation(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding); - // Make a copy the HitTestLocation in a new region by applying given offset to internal point and area. - HitTestLocation(const HitTestLocation&, const LayoutSize& offset, RenderRegion* = 0); + HitTestLocation(const HitTestLocation&, const LayoutSize& offset); HitTestLocation(const HitTestLocation&); ~HitTestLocation(); HitTestLocation& operator=(const HitTestLocation&); @@ -59,8 +50,6 @@ public: const LayoutPoint& point() const { return m_point; } IntPoint roundedPoint() const { return roundedIntPoint(m_point); } - RenderRegion* region() const { return m_region; } - // Rect-based hit test related methods. bool isRectBasedTest() const { return m_isRectBased; } bool isRectilinear() const { return m_isRectilinear; } @@ -91,8 +80,6 @@ private: FloatPoint m_transformedPoint; FloatQuad m_transformedRect; - RenderRegion* m_region; // The region we're inside. - bool m_isRectBased; bool m_isRectilinear; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/HitTestRequest.h b/chromium/third_party/WebKit/Source/core/rendering/HitTestRequest.h index 97dfa5165a7..c8a63ef9c49 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/HitTestRequest.h +++ b/chromium/third_party/WebKit/Source/core/rendering/HitTestRequest.h @@ -40,7 +40,7 @@ public: AllowFrameScrollbars = 1 << 9, AllowChildFrameContent = 1 << 10, ChildFrameHitTest = 1 << 11, - IgnorePointerEventsNone = 1 << 12 + IgnorePointerEventsNone = 1 << 12, }; typedef unsigned HitTestRequestType; diff --git a/chromium/third_party/WebKit/Source/core/rendering/HitTestResult.cpp b/chromium/third_party/WebKit/Source/core/rendering/HitTestResult.cpp index ad4e162801f..bce50193911 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/HitTestResult.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/HitTestResult.cpp @@ -22,26 +22,23 @@ #include "config.h" #include "core/rendering/HitTestResult.h" -#include "HTMLNames.h" -#include "SVGNames.h" -#include "XLinkNames.h" +#include "core/HTMLNames.h" +#include "core/XLinkNames.h" #include "core/dom/DocumentMarkerController.h" #include "core/dom/NodeRenderingTraversal.h" #include "core/dom/shadow/ShadowRoot.h" #include "core/editing/FrameSelection.h" #include "core/fetch/ImageResource.h" +#include "core/frame/LocalFrame.h" #include "core/html/HTMLAnchorElement.h" -#include "core/html/HTMLAreaElement.h" #include "core/html/HTMLImageElement.h" #include "core/html/HTMLInputElement.h" #include "core/html/HTMLMediaElement.h" -#include "core/html/HTMLTextAreaElement.h" -#include "core/html/HTMLVideoElement.h" #include "core/html/parser/HTMLParserIdioms.h" -#include "core/frame/Frame.h" #include "core/page/FrameTree.h" #include "core/rendering/RenderImage.h" #include "core/rendering/RenderTextFragment.h" +#include "core/svg/SVGElement.h" #include "platform/scroll/Scrollbar.h" namespace WebCore { @@ -91,7 +88,7 @@ HitTestResult::HitTestResult(const HitTestResult& other) , m_isFirstLetter(other.m_isFirstLetter) { // Only copy the NodeSet in case of rect hit test. - m_rectBasedTestResult = adoptPtr(other.m_rectBasedTestResult ? new NodeSet(*other.m_rectBasedTestResult) : 0); + m_rectBasedTestResult = adoptPtrWillBeNoop(other.m_rectBasedTestResult ? new NodeSet(*other.m_rectBasedTestResult) : 0); } HitTestResult::~HitTestResult() @@ -112,7 +109,7 @@ HitTestResult& HitTestResult::operator=(const HitTestResult& other) m_isOverWidget = other.isOverWidget(); // Only copy the NodeSet in case of rect hit test. - m_rectBasedTestResult = adoptPtr(other.m_rectBasedTestResult ? new NodeSet(*other.m_rectBasedTestResult) : 0); + m_rectBasedTestResult = adoptPtrWillBeNoop(other.m_rectBasedTestResult ? new NodeSet(*other.m_rectBasedTestResult) : 0); return *this; } @@ -182,7 +179,7 @@ void HitTestResult::setScrollbar(Scrollbar* s) m_scrollbar = s; } -Frame* HitTestResult::innerNodeFrame() const +LocalFrame* HitTestResult::innerNodeFrame() const { if (m_innerNonSharedNode) return m_innerNonSharedNode->document().frame(); @@ -191,24 +188,12 @@ Frame* HitTestResult::innerNodeFrame() const return 0; } -Frame* HitTestResult::targetFrame() const -{ - if (!m_innerURLElement) - return 0; - - Frame* frame = m_innerURLElement->document().frame(); - if (!frame) - return 0; - - return frame->tree().find(m_innerURLElement->target()); -} - bool HitTestResult::isSelected() const { if (!m_innerNonSharedNode) return false; - if (Frame* frame = m_innerNonSharedNode->document().frame()) + if (LocalFrame* frame = m_innerNonSharedNode->document().frame()) return frame->selection().contains(m_hitTestLocation.point()); return false; } @@ -221,7 +206,7 @@ String HitTestResult::spellingToolTip(TextDirection& dir) const if (!m_innerNonSharedNode) return String(); - DocumentMarker* marker = m_innerNonSharedNode->document().markers()->markerContainingPoint(m_hitTestLocation.point(), DocumentMarker::Grammar); + DocumentMarker* marker = m_innerNonSharedNode->document().markers().markerContainingPoint(m_hitTestLocation.point(), DocumentMarker::Grammar); if (!marker) return String(); @@ -253,14 +238,14 @@ const AtomicString& HitTestResult::altDisplayString() const if (!m_innerNonSharedNode) return nullAtom; - if (m_innerNonSharedNode->hasTagName(imgTag)) { - HTMLImageElement* image = toHTMLImageElement(m_innerNonSharedNode); - return image->getAttribute(altAttr); + if (isHTMLImageElement(*m_innerNonSharedNode)) { + HTMLImageElement& image = toHTMLImageElement(*m_innerNonSharedNode); + return image.getAttribute(altAttr); } - if (m_innerNonSharedNode->hasTagName(inputTag)) { - HTMLInputElement* input = toHTMLInputElement(m_innerNonSharedNode); - return input->alt(); + if (isHTMLInputElement(*m_innerNonSharedNode)) { + HTMLInputElement& input = toHTMLInputElement(*m_innerNonSharedNode); + return input.alt(); } return nullAtom; @@ -293,17 +278,19 @@ KURL HitTestResult::absoluteImageURL() const if (!m_innerNonSharedNode) return KURL(); - if (!(m_innerNonSharedNode->renderer() && m_innerNonSharedNode->renderer()->isImage())) + RenderObject* renderer = m_innerNonSharedNode->renderer(); + if (!(renderer && (renderer->isImage() || renderer->isCanvas()))) return KURL(); AtomicString urlString; - if (m_innerNonSharedNode->hasTagName(embedTag) - || m_innerNonSharedNode->hasTagName(imgTag) - || m_innerNonSharedNode->hasTagName(inputTag) - || m_innerNonSharedNode->hasTagName(objectTag) - || m_innerNonSharedNode->hasTagName(SVGNames::imageTag) + if (isHTMLCanvasElement(*m_innerNonSharedNode) + || isHTMLEmbedElement(*m_innerNonSharedNode) + || isHTMLImageElement(*m_innerNonSharedNode) + || isHTMLInputElement(*m_innerNonSharedNode) + || isHTMLObjectElement(*m_innerNonSharedNode) + || isSVGImageElement(*m_innerNonSharedNode) ) { - urlString = toElement(m_innerNonSharedNode)->imageSourceURL(); + urlString = toElement(*m_innerNonSharedNode).imageSourceURL(); } else return KURL(); @@ -325,8 +312,8 @@ HTMLMediaElement* HitTestResult::mediaElement() const if (!(m_innerNonSharedNode->renderer() && m_innerNonSharedNode->renderer()->isMedia())) return 0; - if (isHTMLVideoElement(m_innerNonSharedNode.get()) || m_innerNonSharedNode->hasTagName(HTMLNames::audioTag)) - return toHTMLMediaElement(m_innerNonSharedNode.get()); + if (isHTMLMediaElement(*m_innerNonSharedNode)) + return toHTMLMediaElement(m_innerNonSharedNode); return 0; } @@ -336,9 +323,9 @@ KURL HitTestResult::absoluteLinkURL() const return KURL(); AtomicString urlString; - if (isHTMLAnchorElement(m_innerURLElement.get()) || isHTMLAreaElement(m_innerURLElement.get()) || m_innerURLElement->hasTagName(linkTag)) + if (isHTMLAnchorElement(*m_innerURLElement) || isHTMLAreaElement(*m_innerURLElement) || isHTMLLinkElement(*m_innerURLElement)) urlString = m_innerURLElement->getAttribute(hrefAttr); - else if (m_innerURLElement->hasTagName(SVGNames::aTag)) + else if (isSVGAElement(*m_innerURLElement)) urlString = m_innerURLElement->getAttribute(XLinkNames::hrefAttr); else return KURL(); @@ -351,10 +338,10 @@ bool HitTestResult::isLiveLink() const if (!m_innerURLElement) return false; - if (isHTMLAnchorElement(m_innerURLElement.get())) + if (isHTMLAnchorElement(*m_innerURLElement)) return toHTMLAnchorElement(m_innerURLElement)->isLiveLink(); - if (m_innerURLElement->hasTagName(SVGNames::aTag)) + if (isSVGAElement(*m_innerURLElement)) return m_innerURLElement->isLink(); return false; @@ -362,12 +349,12 @@ bool HitTestResult::isLiveLink() const bool HitTestResult::isMisspelled() const { - if (!targetNode()) + if (!targetNode() || !targetNode()->renderer()) return false; VisiblePosition pos(targetNode()->renderer()->positionForPoint(localPoint())); if (pos.isNull()) return false; - return m_innerNonSharedNode->document().markers()->markersInRange( + return m_innerNonSharedNode->document().markers().markersInRange( makeRange(pos, pos).get(), DocumentMarker::MisspellingMarkers()).size() > 0; } @@ -376,14 +363,6 @@ bool HitTestResult::isOverLink() const return m_innerURLElement && m_innerURLElement->isLink(); } -String HitTestResult::titleDisplayString() const -{ - if (!m_innerURLElement) - return String(); - - return m_innerURLElement->title(); -} - String HitTestResult::textContent() const { if (!m_innerURLElement) @@ -400,11 +379,11 @@ bool HitTestResult::isContentEditable() const if (!m_innerNonSharedNode) return false; - if (isHTMLTextAreaElement(m_innerNonSharedNode.get())) + if (isHTMLTextAreaElement(*m_innerNonSharedNode)) return true; - if (m_innerNonSharedNode->hasTagName(inputTag)) - return toHTMLInputElement(m_innerNonSharedNode)->isTextField(); + if (isHTMLInputElement(*m_innerNonSharedNode)) + return toHTMLInputElement(*m_innerNonSharedNode).isTextField(); return m_innerNonSharedNode->rendererIsEditable(); } @@ -477,14 +456,14 @@ void HitTestResult::append(const HitTestResult& other) const HitTestResult::NodeSet& HitTestResult::rectBasedTestResult() const { if (!m_rectBasedTestResult) - m_rectBasedTestResult = adoptPtr(new NodeSet); + m_rectBasedTestResult = adoptPtrWillBeNoop(new NodeSet); return *m_rectBasedTestResult; } HitTestResult::NodeSet& HitTestResult::mutableRectBasedTestResult() { if (!m_rectBasedTestResult) - m_rectBasedTestResult = adoptPtr(new NodeSet); + m_rectBasedTestResult = adoptPtrWillBeNoop(new NodeSet); return *m_rectBasedTestResult; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/HitTestResult.h b/chromium/third_party/WebKit/Source/core/rendering/HitTestResult.h index 490596e4035..4db557a1fc1 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/HitTestResult.h +++ b/chromium/third_party/WebKit/Source/core/rendering/HitTestResult.h @@ -27,6 +27,7 @@ #include "platform/geometry/FloatQuad.h" #include "platform/geometry/FloatRect.h" #include "platform/geometry/LayoutRect.h" +#include "platform/heap/Handle.h" #include "platform/text/TextDirection.h" #include "wtf/Forward.h" #include "wtf/ListHashSet.h" @@ -36,18 +37,17 @@ namespace WebCore { class Element; -class Frame; +class LocalFrame; class HTMLMediaElement; class Image; class KURL; class Node; class RenderObject; -class RenderRegion; class Scrollbar; class HitTestResult { public: - typedef ListHashSet<RefPtr<Node> > NodeSet; + typedef WillBeHeapListHashSet<RefPtrWillBeMember<Node> > NodeSet; HitTestResult(); HitTestResult(const LayoutPoint&); @@ -76,7 +76,7 @@ public: // The hit-tested point in the coordinates of the innerNode frame, the frame containing innerNode. const LayoutPoint& pointInInnerNodeFrame() const { return m_pointInInnerNodeFrame; } IntPoint roundedPointInInnerNodeFrame() const { return roundedIntPoint(pointInInnerNodeFrame()); } - Frame* innerNodeFrame() const; + LocalFrame* innerNodeFrame() const; // The hit-tested point in the coordinates of the inner node. const LayoutPoint& localPoint() const { return m_localPoint; } @@ -96,12 +96,10 @@ public: void setIsFirstLetter(bool b) { m_isFirstLetter = b; } void setIsOverWidget(bool b) { m_isOverWidget = b; } - Frame* targetFrame() const; bool isSelected() const; String spellingToolTip(TextDirection&) const; String title(TextDirection&) const; const AtomicString& altDisplayString() const; - String titleDisplayString() const; Image* image() const; IntRect imageRect() const; KURL absoluteImageURL() const; @@ -132,18 +130,18 @@ private: HitTestLocation m_hitTestLocation; - RefPtr<Node> m_innerNode; - RefPtr<Node> m_innerPossiblyPseudoNode; - RefPtr<Node> m_innerNonSharedNode; + RefPtrWillBePersistent<Node> m_innerNode; + RefPtrWillBePersistent<Node> m_innerPossiblyPseudoNode; + RefPtrWillBePersistent<Node> m_innerNonSharedNode; LayoutPoint m_pointInInnerNodeFrame; // The hit-tested point in innerNode frame coordinates. LayoutPoint m_localPoint; // A point in the local coordinate space of m_innerNonSharedNode's renderer. Allows us to efficiently // determine where inside the renderer we hit on subsequent operations. - RefPtr<Element> m_innerURLElement; + RefPtrWillBePersistent<Element> m_innerURLElement; RefPtr<Scrollbar> m_scrollbar; bool m_isOverWidget; // Returns true if we are over a widget (and not in the border/padding area of a RenderWidget for example). bool m_isFirstLetter; - mutable OwnPtr<NodeSet> m_rectBasedTestResult; + mutable OwnPtrWillBePersistent<NodeSet> m_rectBasedTestResult; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/ImageQualityController.cpp b/chromium/third_party/WebKit/Source/core/rendering/ImageQualityController.cpp index ef4c23b73c8..09751291106 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/ImageQualityController.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/ImageQualityController.cpp @@ -31,8 +31,8 @@ #include "config.h" #include "core/rendering/ImageQualityController.h" -#include "core/frame/Frame.h" #include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "platform/graphics/GraphicsContext.h" namespace WebCore { @@ -60,6 +60,21 @@ void ImageQualityController::remove(RenderObject* renderer) } } +InterpolationQuality ImageQualityController::chooseInterpolationQuality(GraphicsContext* context, RenderObject* object, Image* image, const void* layer, const LayoutSize& layoutSize) +{ + if (InterpolationDefault == InterpolationLow) + return InterpolationLow; + + if (shouldPaintAtLowQuality(context, object, image, layer, layoutSize)) + return InterpolationLow; + + // For images that are potentially animated we paint them at medium quality. + if (image && image->maybeAnimated()) + return InterpolationMedium; + + return InterpolationDefault; +} + ImageQualityController::~ImageQualityController() { // This will catch users of ImageQualityController that forget to call cleanUp. @@ -109,14 +124,14 @@ void ImageQualityController::highQualityRepaintTimerFired(Timer<ImageQualityCont m_animatedResizeIsActive = false; for (ObjectLayerSizeMap::iterator it = m_objectLayerSizeMap.begin(); it != m_objectLayerSizeMap.end(); ++it) { - if (Frame* frame = it->key->document().frame()) { + if (LocalFrame* frame = it->key->document().frame()) { // If this renderer's containing FrameView is in live resize, punt the timer and hold back for now. if (frame->view() && frame->view()->inLiveResize()) { restartTimer(); return; } } - it->key->repaint(); + it->key->paintInvalidationForWholeRenderer(); } m_liveResizeOptimizationIsActive = false; @@ -124,7 +139,7 @@ void ImageQualityController::highQualityRepaintTimerFired(Timer<ImageQualityCont void ImageQualityController::restartTimer() { - m_timer.startOneShot(cLowQualityTimeThreshold); + m_timer.startOneShot(cLowQualityTimeThreshold, FROM_HERE); } bool ImageQualityController::shouldPaintAtLowQuality(GraphicsContext* context, RenderObject* object, Image* image, const void *layer, const LayoutSize& layoutSize) @@ -159,7 +174,7 @@ bool ImageQualityController::shouldPaintAtLowQuality(GraphicsContext* context, R LayoutSize scaledLayoutSize = currentTransform.mapSize(roundedIntSize(layoutSize)); // If the containing FrameView is being resized, paint at low quality until resizing is finished. - if (Frame* frame = object->document().frame()) { + if (LocalFrame* frame = object->document().frame()) { bool frameViewIsCurrentlyInLiveResize = frame->view() && frame->view()->inLiveResize(); if (frameViewIsCurrentlyInLiveResize) { set(object, innerMap, layer, scaledLayoutSize); @@ -174,6 +189,9 @@ bool ImageQualityController::shouldPaintAtLowQuality(GraphicsContext* context, R } } + // See crbug.com/382491. This test is insufficient to ensure that there is no scale + // applied in the compositor, but it is probably adequate here. In the worst case we + // draw at high quality when we need not. if (!contextIsScaled && scaledLayoutSize == scaledImageSize) { // There is no scale in effect. If we had a scale in effect before, we can just remove this object from the list. removeLayer(object, innerMap, layer); diff --git a/chromium/third_party/WebKit/Source/core/rendering/ImageQualityController.h b/chromium/third_party/WebKit/Source/core/rendering/ImageQualityController.h index a9e8b108d88..71544283b8f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/ImageQualityController.h +++ b/chromium/third_party/WebKit/Source/core/rendering/ImageQualityController.h @@ -53,11 +53,12 @@ public: static void remove(RenderObject*); - bool shouldPaintAtLowQuality(GraphicsContext*, RenderObject*, Image*, const void* layer, const LayoutSize&); + InterpolationQuality chooseInterpolationQuality(GraphicsContext*, RenderObject*, Image*, const void* layer, const LayoutSize&); private: ImageQualityController(); + bool shouldPaintAtLowQuality(GraphicsContext*, RenderObject*, Image*, const void* layer, const LayoutSize&); void removeLayer(RenderObject*, LayerSizeMap* innerMap, const void* layer); void set(RenderObject*, LayerSizeMap* innerMap, const void* layer, const LayoutSize&); void objectDestroyed(RenderObject*); diff --git a/chromium/third_party/WebKit/Source/core/rendering/InlineBox.cpp b/chromium/third_party/WebKit/Source/core/rendering/InlineBox.cpp index 0e1e21ea874..9ec715c6e63 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/InlineBox.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/InlineBox.cpp @@ -58,10 +58,10 @@ InlineBox::~InlineBox() #endif -void InlineBox::remove() +void InlineBox::remove(MarkLineBoxes markLineBoxes) { if (parent()) - parent()->removeChild(this); + parent()->removeChild(this, markLineBoxes); } void* InlineBox::operator new(size_t sz) @@ -82,14 +82,12 @@ const char* InlineBox::boxName() const void InlineBox::showTreeForThis() const { - if (m_renderer) - m_renderer->showTreeForThis(); + renderer().showTreeForThis(); } void InlineBox::showLineTreeForThis() const { - if (m_renderer) - m_renderer->containingBlock()->showLineTreeAndMark(this, "*"); + renderer().containingBlock()->showLineTreeAndMark(this, "*"); } void InlineBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj, int depth) const @@ -99,7 +97,7 @@ void InlineBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* mar printedCharacters += fprintf(stderr, "%s", markedLabel1); if (this == markedBox2) printedCharacters += fprintf(stderr, "%s", markedLabel2); - if (renderer() == obj) + if (&renderer() == obj) printedCharacters += fprintf(stderr, "*"); for (; printedCharacters < depth * 2; printedCharacters++) fputc(' ', stderr); @@ -112,7 +110,10 @@ void InlineBox::showBox(int printedCharacters) const printedCharacters += fprintf(stderr, "%s\t%p", boxName(), this); for (; printedCharacters < showTreeCharacterOffset; printedCharacters++) fputc(' ', stderr); - fprintf(stderr, "\t%s %p\n", renderer() ? renderer()->renderName() : "No Renderer", renderer()); + fprintf(stderr, "\t%s %p {pos=%g,%g size=%g,%g} baseline=%i/%i\n", + renderer().renderName(), &renderer(), x(), y(), width(), height(), + baselinePosition(AlphabeticBaseline), + baselinePosition(IdeographicBaseline)); } #endif @@ -121,14 +122,14 @@ float InlineBox::logicalHeight() const if (hasVirtualLogicalHeight()) return virtualLogicalHeight(); - if (renderer()->isText()) - return m_bitfields.isText() ? renderer()->style(isFirstLineStyle())->fontMetrics().height() : 0; - if (renderer()->isBox() && parent()) - return isHorizontal() ? toRenderBox(m_renderer)->height() : toRenderBox(m_renderer)->width(); + if (renderer().isText()) + return m_bitfields.isText() ? renderer().style(isFirstLineStyle())->fontMetrics().height() : 0; + if (renderer().isBox() && parent()) + return isHorizontal() ? toRenderBox(renderer()).height().toFloat() : toRenderBox(renderer()).width().toFloat(); ASSERT(isInlineFlowBox()); RenderBoxModelObject* flowObject = boxModelObject(); - const FontMetrics& fontMetrics = renderer()->style(isFirstLineStyle())->fontMetrics(); + const FontMetrics& fontMetrics = renderer().style(isFirstLineStyle())->fontMetrics(); float result = fontMetrics.height(); if (parent()) result += flowObject->borderAndPaddingLogicalHeight(); @@ -147,12 +148,12 @@ LayoutUnit InlineBox::lineHeight() const int InlineBox::caretMinOffset() const { - return m_renderer->caretMinOffset(); + return renderer().caretMinOffset(); } int InlineBox::caretMaxOffset() const { - return m_renderer->caretMaxOffset(); + return renderer().caretMaxOffset(); } void InlineBox::dirtyLineBoxes() @@ -164,43 +165,43 @@ void InlineBox::dirtyLineBoxes() void InlineBox::deleteLine() { - if (!m_bitfields.extracted() && m_renderer->isBox()) - toRenderBox(m_renderer)->setInlineBoxWrapper(0); + if (!m_bitfields.extracted() && renderer().isBox()) + toRenderBox(renderer()).setInlineBoxWrapper(0); destroy(); } void InlineBox::extractLine() { m_bitfields.setExtracted(true); - if (m_renderer->isBox()) - toRenderBox(m_renderer)->setInlineBoxWrapper(0); + if (renderer().isBox()) + toRenderBox(renderer()).setInlineBoxWrapper(0); } void InlineBox::attachLine() { m_bitfields.setExtracted(false); - if (m_renderer->isBox()) - toRenderBox(m_renderer)->setInlineBoxWrapper(this); + if (renderer().isBox()) + toRenderBox(renderer()).setInlineBoxWrapper(this); } void InlineBox::adjustPosition(float dx, float dy) { m_topLeft.move(dx, dy); - if (m_renderer->isReplaced()) - toRenderBox(m_renderer)->move(dx, dy); + if (renderer().isReplaced()) + toRenderBox(renderer()).move(dx, dy); } void InlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) { - if (!paintInfo.shouldPaintWithinRoot(renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)) + if (!paintInfo.shouldPaintWithinRoot(&renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)) return; LayoutPoint childPoint = paintOffset; - if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock(). - childPoint = renderer()->containingBlock()->flipForWritingModeForChild(toRenderBox(renderer()), childPoint); + if (parent()->renderer().style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock(). + childPoint = renderer().containingBlock()->flipForWritingModeForChild(&toRenderBox(renderer()), childPoint); - RenderBlock::paintAsInlineBlock(renderer(), paintInfo, childPoint); + RenderBlock::paintAsInlineBlock(&renderer(), paintInfo, childPoint); } bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) @@ -209,26 +210,26 @@ bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1 // specification.) LayoutPoint childPoint = accumulatedOffset; - if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock(). - childPoint = renderer()->containingBlock()->flipForWritingModeForChild(toRenderBox(renderer()), childPoint); + if (parent()->renderer().style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock(). + childPoint = renderer().containingBlock()->flipForWritingModeForChild(&toRenderBox(renderer()), childPoint); - return renderer()->hitTest(request, result, locationInContainer, childPoint); + return renderer().hitTest(request, result, locationInContainer, childPoint); } -const RootInlineBox* InlineBox::root() const +const RootInlineBox& InlineBox::root() const { if (m_parent) return m_parent->root(); ASSERT(isRootInlineBox()); - return static_cast<const RootInlineBox*>(this); + return static_cast<const RootInlineBox&>(*this); } -RootInlineBox* InlineBox::root() +RootInlineBox& InlineBox::root() { if (m_parent) return m_parent->root(); ASSERT(isRootInlineBox()); - return static_cast<RootInlineBox*>(this); + return static_cast<RootInlineBox&>(*this); } bool InlineBox::nextOnLineExists() const @@ -284,13 +285,13 @@ InlineBox* InlineBox::prevLeafChildIgnoringLineBreak() const RenderObject::SelectionState InlineBox::selectionState() { - return renderer()->selectionState(); + return renderer().selectionState(); } bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const { // Non-replaced elements can always accommodate an ellipsis. - if (!m_renderer || !m_renderer->isReplaced()) + if (!renderer().isReplaced()) return true; IntRect boxRect(left(), 0, m_logicalWidth, 10); @@ -314,41 +315,41 @@ void InlineBox::clearKnownToHaveNoOverflow() FloatPoint InlineBox::locationIncludingFlipping() { - if (!renderer()->style()->isFlippedBlocksWritingMode()) + if (!renderer().style()->isFlippedBlocksWritingMode()) return FloatPoint(x(), y()); - RenderBlockFlow* block = root()->block(); - if (block->style()->isHorizontalWritingMode()) - return FloatPoint(x(), block->height() - height() - y()); - else - return FloatPoint(block->width() - width() - x(), y()); + RenderBlockFlow& block = root().block(); + if (block.style()->isHorizontalWritingMode()) + return FloatPoint(x(), block.height() - height() - y()); + + return FloatPoint(block.width() - width() - x(), y()); } void InlineBox::flipForWritingMode(FloatRect& rect) { - if (!renderer()->style()->isFlippedBlocksWritingMode()) + if (!renderer().style()->isFlippedBlocksWritingMode()) return; - root()->block()->flipForWritingMode(rect); + root().block().flipForWritingMode(rect); } FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point) { - if (!renderer()->style()->isFlippedBlocksWritingMode()) + if (!renderer().style()->isFlippedBlocksWritingMode()) return point; - return root()->block()->flipForWritingMode(point); + return root().block().flipForWritingMode(point); } void InlineBox::flipForWritingMode(LayoutRect& rect) { - if (!renderer()->style()->isFlippedBlocksWritingMode()) + if (!renderer().style()->isFlippedBlocksWritingMode()) return; - root()->block()->flipForWritingMode(rect); + root().block().flipForWritingMode(rect); } LayoutPoint InlineBox::flipForWritingMode(const LayoutPoint& point) { - if (!renderer()->style()->isFlippedBlocksWritingMode()) + if (!renderer().style()->isFlippedBlocksWritingMode()) return point; - return root()->block()->flipForWritingMode(point); + return root().block().flipForWritingMode(point); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/InlineBox.h b/chromium/third_party/WebKit/Source/core/rendering/InlineBox.h index 5803cd17e2b..f319c846d5d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/InlineBox.h +++ b/chromium/third_party/WebKit/Source/core/rendering/InlineBox.h @@ -30,11 +30,14 @@ class HitTestRequest; class HitTestResult; class RootInlineBox; +enum MarkLineBoxes { MarkLineBoxesDirty, DontMarkLineBoxes }; + // InlineBox represents a rectangle that occurs on a line. It corresponds to // some RenderObject (i.e., it represents a portion of that RenderObject). class InlineBox { + WTF_MAKE_NONCOPYABLE(InlineBox); public: - InlineBox(RenderObject* obj) + InlineBox(RenderObject& obj) : m_next(0) , m_prev(0) , m_parent(0) @@ -46,7 +49,7 @@ public: { } - InlineBox(RenderObject* obj, FloatPoint topLeft, float logicalWidth, bool firstLine, bool constructed, + InlineBox(RenderObject& obj, FloatPoint topLeft, float logicalWidth, bool firstLine, bool constructed, bool dirty, bool extracted, bool isHorizontal, InlineBox* next, InlineBox* prev, InlineFlowBox* parent) : m_next(next) , m_prev(prev) @@ -146,7 +149,7 @@ public: void setFirstLineStyleBit(bool firstLine) { m_bitfields.setFirstLine(firstLine); } bool isFirstLineStyle() const { return m_bitfields.firstLine(); } - void remove(); + void remove(MarkLineBoxes = MarkLineBoxesDirty); InlineBox* nextOnLine() const { return m_next; } InlineBox* prevOnLine() const { return m_prev; } @@ -173,7 +176,7 @@ public: InlineBox* nextLeafChildIgnoringLineBreak() const; InlineBox* prevLeafChildIgnoringLineBreak() const; - RenderObject* renderer() const { return m_renderer; } + RenderObject& renderer() const { return m_renderer; } InlineFlowBox* parent() const { @@ -182,8 +185,8 @@ public: } void setParent(InlineFlowBox* par) { m_parent = par; } - const RootInlineBox* root() const; - RootInlineBox* root(); + const RootInlineBox& root() const; + RootInlineBox& root(); // x() is the left side of the box in the containing block's coordinate system. void setX(float x) { m_topLeft.setX(x); } @@ -254,7 +257,7 @@ public: virtual void clearTruncation() { } bool isDirty() const { return m_bitfields.dirty(); } - virtual void markDirty(bool dirty = true) { m_bitfields.setDirty(dirty); } + virtual void markDirty() { m_bitfields.setDirty(true); } virtual void dirtyLineBoxes(); @@ -270,15 +273,15 @@ public: int expansion() const { return m_bitfields.expansion(); } - bool visibleToHitTestRequest(const HitTestRequest& request) const { return renderer()->visibleToHitTestRequest(request); } + bool visibleToHitTestRequest(const HitTestRequest& request) const { return renderer().visibleToHitTestRequest(request); } - EVerticalAlign verticalAlign() const { return renderer()->style(m_bitfields.firstLine())->verticalAlign(); } + EVerticalAlign verticalAlign() const { return renderer().style(m_bitfields.firstLine())->verticalAlign(); } // Use with caution! The type is not checked! RenderBoxModelObject* boxModelObject() const { - if (!m_renderer->isText()) - return toRenderBoxModelObject(m_renderer); + if (!renderer().isText()) + return toRenderBoxModelObject(&renderer()); return 0; } @@ -377,6 +380,7 @@ private: InlineBox* m_prev; // The previous element on the same line as us. InlineFlowBox* m_parent; // The box that contains us. + RenderObject& m_renderer; protected: // For RootInlineBox @@ -398,8 +402,6 @@ protected: // For InlineFlowBox and InlineTextBox bool extracted() const { return m_bitfields.extracted(); } - RenderObject* m_renderer; - FloatPoint m_topLeft; float m_logicalWidth; @@ -427,6 +429,14 @@ inline void InlineBox::setHasBadParent() #define DEFINE_INLINE_BOX_TYPE_CASTS(typeName) \ DEFINE_TYPE_CASTS(typeName, InlineBox, box, box->is##typeName(), box.is##typeName()) +// Allow equality comparisons of InlineBox's by reference or pointer, interchangeably. +inline bool operator==(const InlineBox& a, const InlineBox& b) { return &a == &b; } +inline bool operator==(const InlineBox& a, const InlineBox* b) { return &a == b; } +inline bool operator==(const InlineBox* a, const InlineBox& b) { return a == &b; } +inline bool operator!=(const InlineBox& a, const InlineBox& b) { return !(a == b); } +inline bool operator!=(const InlineBox& a, const InlineBox* b) { return !(a == b); } +inline bool operator!=(const InlineBox* a, const InlineBox& b) { return !(a == b); } + } // namespace WebCore #ifndef NDEBUG diff --git a/chromium/third_party/WebKit/Source/core/rendering/InlineFlowBox.cpp b/chromium/third_party/WebKit/Source/core/rendering/InlineFlowBox.cpp index 68952fc6e18..b3384b2e33c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/InlineFlowBox.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/InlineFlowBox.cpp @@ -20,7 +20,7 @@ #include "config.h" #include "core/rendering/InlineFlowBox.h" -#include "CSSPropertyNames.h" +#include "core/CSSPropertyNames.h" #include "core/dom/Document.h" #include "core/rendering/HitTestResult.h" #include "core/rendering/InlineTextBox.h" @@ -109,7 +109,7 @@ void InlineFlowBox::addToLine(InlineBox* child) child->setFirstLineStyleBit(isFirstLineStyle()); child->setIsHorizontal(isHorizontal()); if (child->isText()) { - if (child->renderer()->parent() == renderer()) + if (child->renderer().parent() == renderer()) m_hasTextChildren = true; setHasTextDescendantsOnAncestors(this); } else if (child->isInlineFlowBox()) { @@ -117,14 +117,14 @@ void InlineFlowBox::addToLine(InlineBox* child) setHasTextDescendantsOnAncestors(this); } - if (descendantsHaveSameLineHeightAndBaseline() && !child->renderer()->isOutOfFlowPositioned()) { - RenderStyle* parentStyle = renderer()->style(isFirstLineStyle()); - RenderStyle* childStyle = child->renderer()->style(isFirstLineStyle()); + if (descendantsHaveSameLineHeightAndBaseline() && !child->renderer().isOutOfFlowPositioned()) { + RenderStyle* parentStyle = renderer().style(isFirstLineStyle()); + RenderStyle* childStyle = child->renderer().style(isFirstLineStyle()); bool shouldClearDescendantsHaveSameLineHeightAndBaseline = false; - if (child->renderer()->isReplaced()) + if (child->renderer().isReplaced()) shouldClearDescendantsHaveSameLineHeightAndBaseline = true; else if (child->isText()) { - if (child->renderer()->isBR() || child->renderer()->parent() != renderer()) { + if (child->renderer().isBR() || child->renderer().parent() != renderer()) { if (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics()) || parentStyle->lineHeight() != childStyle->lineHeight() || (parentStyle->verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle->verticalAlign() != BASELINE) @@ -133,7 +133,7 @@ void InlineFlowBox::addToLine(InlineBox* child) if (childStyle->hasTextCombine() || childStyle->textEmphasisMark() != TextEmphasisMarkNone) shouldClearDescendantsHaveSameLineHeightAndBaseline = true; } else { - if (child->renderer()->isBR()) { + if (child->renderer().isBR()) { // FIXME: This is dumb. We only turn off because current layout test results expect the <br> to be 0-height on the baseline. // Other than making a zillion tests have to regenerate results, there's no reason to ditch the optimization here. shouldClearDescendantsHaveSameLineHeightAndBaseline = true; @@ -154,19 +154,21 @@ void InlineFlowBox::addToLine(InlineBox* child) clearDescendantsHaveSameLineHeightAndBaseline(); } - if (!child->renderer()->isOutOfFlowPositioned()) { + if (!child->renderer().isOutOfFlowPositioned()) { if (child->isText()) { - RenderStyle* childStyle = child->renderer()->style(isFirstLineStyle()); + 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()) + } 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(isFirstLineStyle())->boxShadow() || child->boxModelObject()->hasSelfPaintingLayer() - || (child->renderer()->isListMarker() && !toRenderListMarker(child->renderer())->isInside()) - || child->renderer()->style(isFirstLineStyle())->hasBorderImageOutsets())) + } else if (!child->renderer().isBR() && (child->renderer().style(isFirstLineStyle())->boxShadow() || child->boxModelObject()->hasSelfPaintingLayer() + || (child->renderer().isListMarker() && !toRenderListMarker(child->renderer()).isInside()) + || child->renderer().style(isFirstLineStyle())->hasBorderImageOutsets() + || child->renderer().style(isFirstLineStyle())->hasOutline())) { child->clearKnownToHaveNoOverflow(); + } if (knownToHaveNoOverflow() && child->isInlineFlowBox() && !toInlineFlowBox(child)->knownToHaveNoOverflow()) clearKnownToHaveNoOverflow(); @@ -175,14 +177,14 @@ void InlineFlowBox::addToLine(InlineBox* child) checkConsistency(); } -void InlineFlowBox::removeChild(InlineBox* child) +void InlineFlowBox::removeChild(InlineBox* child, MarkLineBoxes markDirty) { checkConsistency(); - if (!isDirty()) + if (markDirty == MarkLineBoxesDirty && !isDirty()) dirtyLineBoxes(); - root()->childRemoved(child); + root().childRemoved(child); if (child == m_firstChild) m_firstChild = child->nextOnLine(); @@ -222,7 +224,7 @@ void InlineFlowBox::deleteLine() void InlineFlowBox::removeLineBoxFromRenderObject() { - toRenderInline(renderer())->lineBoxes()->removeLineBox(this); + rendererLineBoxes()->removeLineBox(this); } void InlineFlowBox::extractLine() @@ -235,7 +237,7 @@ void InlineFlowBox::extractLine() void InlineFlowBox::extractLineBoxFromRenderObject() { - toRenderInline(renderer())->lineBoxes()->extractLineBox(this); + rendererLineBoxes()->extractLineBox(this); } void InlineFlowBox::attachLine() @@ -248,7 +250,7 @@ void InlineFlowBox::attachLine() void InlineFlowBox::attachLineBoxToRenderObject() { - toRenderInline(renderer())->lineBoxes()->attachLineBox(this); + rendererLineBoxes()->attachLineBox(this); } void InlineFlowBox::adjustPosition(float dx, float dy) @@ -262,7 +264,7 @@ void InlineFlowBox::adjustPosition(float dx, float dy) RenderLineBoxList* InlineFlowBox::rendererLineBoxes() const { - return toRenderInline(renderer())->lineBoxes(); + return toRenderInline(renderer()).lineBoxes(); } static inline bool isLastChildForRenderer(RenderObject* ancestor, RenderObject* child) @@ -276,7 +278,7 @@ static inline bool isLastChildForRenderer(RenderObject* ancestor, RenderObject* RenderObject* curr = child; RenderObject* parent = curr->parent(); while (parent && (!parent->isRenderBlock() || parent->isInline())) { - if (parent->lastChild() != curr) + if (parent->slowLastChild() != curr) return false; if (parent == ancestor) return true; @@ -308,13 +310,13 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, bool isLogically // The root inline box never has borders/margins/padding. if (parent()) { - bool ltr = renderer()->style()->isLeftToRightDirection(); + bool ltr = renderer().style()->isLeftToRightDirection(); // Check to see if all initial lines are unconstructed. If so, then // we know the inline began on this line (unless we are a continuation). RenderLineBoxList* lineBoxList = rendererLineBoxes(); - if (!lineBoxList->firstLineBox()->isConstructed() && !renderer()->isInlineElementContinuation()) { - if (renderer()->style()->boxDecorationBreak() == DCLONE) + if (!lineBoxList->firstLineBox()->isConstructed() && !renderer().isInlineElementContinuation()) { + if (renderer().style()->boxDecorationBreak() == DCLONE) includeLeftEdge = includeRightEdge = true; else if (ltr && lineBoxList->firstLineBox() == this) includeLeftEdge = true; @@ -323,23 +325,23 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, bool isLogically } if (!lineBoxList->lastLineBox()->isConstructed()) { - RenderInline* inlineFlow = toRenderInline(renderer()); - bool isLastObjectOnLine = !isAnsectorAndWithinBlock(renderer(), logicallyLastRunRenderer) || (isLastChildForRenderer(renderer(), logicallyLastRunRenderer) && !isLogicallyLastRunWrapped); + RenderInline& inlineFlow = toRenderInline(renderer()); + bool isLastObjectOnLine = !isAnsectorAndWithinBlock(&renderer(), logicallyLastRunRenderer) || (isLastChildForRenderer(&renderer(), logicallyLastRunRenderer) && !isLogicallyLastRunWrapped); // We include the border under these conditions: // (1) The next line was not created, or it is constructed. We check the previous line for rtl. // (2) The logicallyLastRun is not a descendant of this renderer. // (3) The logicallyLastRun is a descendant of this renderer, but it is the last child of this renderer and it does not wrap to the next line. // (4) The decoration break is set to clone therefore there will be borders on every sides. - if (renderer()->style()->boxDecorationBreak() == DCLONE) + if (renderer().style()->boxDecorationBreak() == DCLONE) includeLeftEdge = includeRightEdge = true; else if (ltr) { if (!nextLineBox() - && ((lastLine || isLastObjectOnLine) && !inlineFlow->continuation())) + && ((lastLine || isLastObjectOnLine) && !inlineFlow.continuation())) includeRightEdge = true; } else { if ((!prevLineBox() || prevLineBox()->isConstructed()) - && ((lastLine || isLastObjectOnLine) && !inlineFlow->continuation())) + && ((lastLine || isLastObjectOnLine) && !inlineFlow.continuation())) includeLeftEdge = true; } } @@ -377,13 +379,13 @@ float InlineFlowBox::placeBoxesInInlineDirection(float logicalLeft, bool& needsW float InlineFlowBox::placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild, float& logicalLeft, float& minLogicalLeft, float& maxLogicalRight, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) { for (InlineBox* curr = firstChild; curr && curr != lastChild; curr = curr->nextOnLine()) { - if (curr->renderer()->isText()) { + if (curr->renderer().isText()) { InlineTextBox* text = toInlineTextBox(curr); - RenderText* rt = toRenderText(text->renderer()); - if (rt->textLength()) { - if (needsWordSpacing && isSpaceOrNewline(rt->characterAt(text->start()))) - logicalLeft += rt->style(isFirstLineStyle())->font().wordSpacing(); - needsWordSpacing = !isSpaceOrNewline(rt->characterAt(text->end())); + RenderText& rt = toRenderText(text->renderer()); + if (rt.textLength()) { + if (needsWordSpacing && isSpaceOrNewline(rt.characterAt(text->start()))) + logicalLeft += rt.style(isFirstLineStyle())->font().fontDescription().wordSpacing(); + needsWordSpacing = !isSpaceOrNewline(rt.characterAt(text->end())); } text->setLogicalLeft(logicalLeft); if (knownToHaveNoOverflow()) @@ -392,17 +394,18 @@ float InlineFlowBox::placeBoxRangeInInlineDirection(InlineBox* firstChild, Inlin if (knownToHaveNoOverflow()) maxLogicalRight = max(logicalLeft, maxLogicalRight); } else { - if (curr->renderer()->isOutOfFlowPositioned()) { - if (curr->renderer()->parent()->style()->isLeftToRightDirection()) + if (curr->renderer().isOutOfFlowPositioned()) { + if (curr->renderer().parent()->style()->isLeftToRightDirection()) { curr->setLogicalLeft(logicalLeft); - else + } else { // Our offset that we cache needs to be from the edge of the right border box and // not the left border box. We have to subtract |x| from the width of the block // (which can be obtained from the root line box). - curr->setLogicalLeft(root()->block()->logicalWidth() - logicalLeft); + curr->setLogicalLeft(root().block().logicalWidth() - logicalLeft); + } continue; // The positioned object has no effect on the width. } - if (curr->renderer()->isRenderInline()) { + if (curr->renderer().isRenderInline()) { InlineFlowBox* flow = toInlineFlowBox(curr); logicalLeft += flow->marginLogicalLeft(); if (knownToHaveNoOverflow()) @@ -411,7 +414,7 @@ float InlineFlowBox::placeBoxRangeInInlineDirection(InlineBox* firstChild, Inlin if (knownToHaveNoOverflow()) maxLogicalRight = max(logicalLeft, maxLogicalRight); logicalLeft += flow->marginLogicalRight(); - } else if (!curr->renderer()->isListMarker() || toRenderListMarker(curr->renderer())->isInside()) { + } else if (!curr->renderer().isListMarker() || toRenderListMarker(curr->renderer()).isInside()) { // The box can have a different writing-mode than the overall line, so this is a bit complicated. // Just get all the physical margin and overflow values by hand based off |isVertical|. LayoutUnit logicalLeftMargin = isHorizontal() ? curr->boxModelObject()->marginLeft() : curr->boxModelObject()->marginTop(); @@ -438,19 +441,19 @@ bool InlineFlowBox::requiresIdeographicBaseline(const GlyphOverflowAndFallbackFo if (isHorizontal()) return false; - if (renderer()->style(isFirstLineStyle())->fontDescription().nonCJKGlyphOrientation() == NonCJKGlyphOrientationUpright - || renderer()->style(isFirstLineStyle())->font().primaryFont()->hasVerticalGlyphs()) + if (renderer().style(isFirstLineStyle())->fontDescription().nonCJKGlyphOrientation() == NonCJKGlyphOrientationUpright + || renderer().style(isFirstLineStyle())->font().primaryFont()->hasVerticalGlyphs()) return true; for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer()->isOutOfFlowPositioned()) + if (curr->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders don't affect calculations. if (curr->isInlineFlowBox()) { if (toInlineFlowBox(curr)->requiresIdeographicBaseline(textBoxDataMap)) return true; } else { - if (curr->renderer()->style(isFirstLineStyle())->font().primaryFont()->hasVerticalGlyphs()) + if (curr->renderer().style(isFirstLineStyle())->font().primaryFont()->hasVerticalGlyphs()) return true; const Vector<const SimpleFontData*>* usedFonts = 0; @@ -476,7 +479,7 @@ void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, i for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { // The computed lineheight needs to be extended for the // positioned elements - if (curr->renderer()->isOutOfFlowPositioned()) + if (curr->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders don't affect calculations. if (curr->verticalAlign() == TOP || curr->verticalAlign() == BOTTOM) { int lineHeight = curr->lineHeight(); @@ -543,7 +546,7 @@ void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox* rootBox, LayoutUnit& return; for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer()->isOutOfFlowPositioned()) + if (curr->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders don't affect calculations. InlineFlowBox* inlineFlowBox = curr->isInlineFlowBox() ? toInlineFlowBox(curr) : 0; @@ -554,7 +557,7 @@ void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox* rootBox, LayoutUnit& // The verticalPositionForBox function returns the distance between the child box's baseline // and the root box's baseline. The value is negative if the child box's baseline is above the // root box's baseline, and it is positive if the child box's baseline is below the root box's baseline. - curr->setLogicalTop(rootBox->verticalPositionForBox(curr, verticalPositionCache)); + curr->setLogicalTop(rootBox->verticalPositionForBox(curr, verticalPositionCache).toFloat()); int ascent = 0; int descent = 0; @@ -600,7 +603,7 @@ void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHei { bool isRootBox = isRootInlineBox(); if (isRootBox) { - const FontMetrics& fontMetrics = renderer()->style(isFirstLineStyle())->fontMetrics(); + 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))); @@ -614,20 +617,20 @@ void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHei } for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer()->isOutOfFlowPositioned()) + if (curr->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders don't affect calculations. if (descendantsHaveSameLineHeightAndBaseline()) { - curr->adjustBlockDirectionPosition(adjustmentForChildrenWithSameLineHeightAndBaseline); + curr->adjustBlockDirectionPosition(adjustmentForChildrenWithSameLineHeightAndBaseline.toFloat()); continue; } InlineFlowBox* inlineFlowBox = curr->isInlineFlowBox() ? toInlineFlowBox(curr) : 0; bool childAffectsTopBottomPos = true; if (curr->verticalAlign() == TOP) - curr->setLogicalTop(top); + curr->setLogicalTop(top.toFloat()); else if (curr->verticalAlign() == BOTTOM) - curr->setLogicalTop(top + maxHeight - curr->lineHeight()); + curr->setLogicalTop((top + maxHeight - curr->lineHeight()).toFloat()); else { if (!strictMode && inlineFlowBox && !inlineFlowBox->hasTextChildren() && !curr->boxModelObject()->hasInlineDirectionBordersOrPadding() && !(inlineFlowBox->descendantsHaveSameLineHeightAndBaseline() && inlineFlowBox->hasTextDescendants())) @@ -642,48 +645,48 @@ void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHei LayoutUnit boxHeightIncludingMargins = boxHeight; if (curr->isText() || curr->isInlineFlowBox()) { - const FontMetrics& fontMetrics = curr->renderer()->style(isFirstLineStyle())->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(isFirstLineStyle())->isHorizontalWritingMode() ? boxObject->borderTop() + boxObject->paddingTop() : - boxObject->borderRight() + boxObject->paddingRight(); + RenderBoxModelObject& boxObject = toRenderBoxModelObject(curr->renderer()); + newLogicalTop -= boxObject.style(isFirstLineStyle())->isHorizontalWritingMode() ? boxObject.borderTop() + boxObject.paddingTop() : + boxObject.borderRight() + boxObject.paddingRight(); } newLogicalTopIncludingMargins = newLogicalTop; - } else if (!curr->renderer()->isBR()) { - RenderBox* box = toRenderBox(curr->renderer()); + } else if (!curr->renderer().isBR()) { + RenderBox& box = toRenderBox(curr->renderer()); newLogicalTopIncludingMargins = newLogicalTop; - LayoutUnit overSideMargin = curr->isHorizontal() ? box->marginTop() : box->marginRight(); - LayoutUnit underSideMargin = curr->isHorizontal() ? box->marginBottom() : box->marginLeft(); + LayoutUnit overSideMargin = curr->isHorizontal() ? box.marginTop() : box.marginRight(); + LayoutUnit underSideMargin = curr->isHorizontal() ? box.marginBottom() : box.marginLeft(); newLogicalTop += overSideMargin; boxHeightIncludingMargins += overSideMargin + underSideMargin; } - curr->setLogicalTop(newLogicalTop); + curr->setLogicalTop(newLogicalTop.toFloat()); if (childAffectsTopBottomPos) { - if (curr->renderer()->isRubyRun()) { + if (curr->renderer().isRubyRun()) { // Treat the leading on the first and last lines of ruby runs as not being part of the overall lineTop/lineBottom. // Really this is a workaround hack for the fact that ruby should have been done as line layout and not done using // inline-block. - if (renderer()->style()->isFlippedLinesWritingMode() == (curr->renderer()->style()->rubyPosition() == RubyPositionAfter)) + if (renderer().style()->isFlippedLinesWritingMode() == (curr->renderer().style()->rubyPosition() == RubyPositionAfter)) hasAnnotationsBefore = true; else hasAnnotationsAfter = true; - RenderRubyRun* rubyRun = toRenderRubyRun(curr->renderer()); - if (RenderRubyBase* rubyBase = rubyRun->rubyBase()) { + RenderRubyRun& rubyRun = toRenderRubyRun(curr->renderer()); + if (RenderRubyBase* rubyBase = rubyRun.rubyBase()) { LayoutUnit bottomRubyBaseLeading = (curr->logicalHeight() - rubyBase->logicalBottom()) + rubyBase->logicalHeight() - (rubyBase->lastRootBox() ? rubyBase->lastRootBox()->lineBottom() : LayoutUnit()); LayoutUnit topRubyBaseLeading = rubyBase->logicalTop() + (rubyBase->firstRootBox() ? rubyBase->firstRootBox()->lineTop() : LayoutUnit()); - newLogicalTop += !renderer()->style()->isFlippedLinesWritingMode() ? topRubyBaseLeading : bottomRubyBaseLeading; + newLogicalTop += !renderer().style()->isFlippedLinesWritingMode() ? topRubyBaseLeading : bottomRubyBaseLeading; boxHeight -= (topRubyBaseLeading + bottomRubyBaseLeading); } } if (curr->isInlineTextBox()) { TextEmphasisPosition emphasisMarkPosition; - if (toInlineTextBox(curr)->getEmphasisMarkPosition(curr->renderer()->style(isFirstLineStyle()), emphasisMarkPosition)) { + if (toInlineTextBox(curr)->getEmphasisMarkPosition(curr->renderer().style(isFirstLineStyle()), emphasisMarkPosition)) { bool emphasisMarkIsOver = emphasisMarkPosition == TextEmphasisPositionOver; - if (emphasisMarkIsOver != curr->renderer()->style(isFirstLineStyle())->isFlippedLinesWritingMode()) + if (emphasisMarkIsOver != curr->renderer().style(isFirstLineStyle())->isFlippedLinesWritingMode()) hasAnnotationsBefore = true; else hasAnnotationsAfter = true; @@ -723,7 +726,7 @@ void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHei lineBottomIncludingMargins = max(lineBottom, lineBottomIncludingMargins); } - if (renderer()->style()->isFlippedLinesWritingMode()) + if (renderer().style()->isFlippedLinesWritingMode()) flipLinesInBlockDirection(lineTopIncludingMargins, lineBottomIncludingMargins); } } @@ -731,7 +734,7 @@ void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHei void InlineFlowBox::computeMaxLogicalTop(float& maxLogicalTop) const { for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer()->isOutOfFlowPositioned()) + if (curr->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders don't affect calculations. if (descendantsHaveSameLineHeightAndBaseline()) @@ -751,7 +754,7 @@ void InlineFlowBox::flipLinesInBlockDirection(LayoutUnit lineTop, LayoutUnit lin setLogicalTop(lineBottom - (logicalTop() - lineTop) - logicalHeight()); for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer()->isOutOfFlowPositioned()) + if (curr->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders aren't affected here. if (curr->isInlineFlowBox()) @@ -767,7 +770,7 @@ inline void InlineFlowBox::addBoxShadowVisualOverflow(LayoutRect& logicalVisualO if (!parent()) return; - RenderStyle* style = renderer()->style(isFirstLineStyle()); + RenderStyle* style = renderer().style(isFirstLineStyle()); if (!style->boxShadow()) return; @@ -800,7 +803,7 @@ inline void InlineFlowBox::addBorderOutsetVisualOverflow(LayoutRect& logicalVisu if (!parent()) return; - RenderStyle* style = renderer()->style(isFirstLineStyle()); + RenderStyle* style = renderer().style(isFirstLineStyle()); if (!style->hasBorderImageOutsets()) return; @@ -829,12 +832,25 @@ inline void InlineFlowBox::addBorderOutsetVisualOverflow(LayoutRect& logicalVisu logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow); } +inline void InlineFlowBox::addOutlineVisualOverflow(LayoutRect& logicalVisualOverflow) +{ + // Outline on root line boxes is applied to the block and not to the lines. + if (!parent()) + return; + + RenderStyle* style = renderer().style(isFirstLineStyle()); + if (!style->hasOutline()) + return; + + logicalVisualOverflow.inflate(style->outlineSize()); +} + inline void InlineFlowBox::addTextBoxVisualOverflow(InlineTextBox* textBox, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, LayoutRect& logicalVisualOverflow) { if (textBox->knownToHaveNoOverflow()) return; - RenderStyle* style = textBox->renderer()->style(isFirstLineStyle()); + RenderStyle* style = textBox->renderer().style(isFirstLineStyle()); GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(textBox); GlyphOverflow* glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->value.second; @@ -862,7 +878,7 @@ inline void InlineFlowBox::addTextBoxVisualOverflow(InlineTextBox* textBox, Glyp // If letter-spacing is negative, we should factor that into right layout overflow. (Even in RTL, letter-spacing is // applied to the right, so this is not an issue with left overflow. - rightGlyphOverflow -= min(0, (int)style->font().letterSpacing()); + rightGlyphOverflow -= min(0, (int)style->font().fontDescription().letterSpacing()); LayoutUnit textShadowLogicalTop; LayoutUnit textShadowLogicalBottom; @@ -891,13 +907,13 @@ inline void InlineFlowBox::addTextBoxVisualOverflow(InlineTextBox* textBox, Glyp inline void InlineFlowBox::addReplacedChildOverflow(const InlineBox* inlineBox, LayoutRect& logicalLayoutOverflow, LayoutRect& logicalVisualOverflow) { - RenderBox* box = toRenderBox(inlineBox->renderer()); + RenderBox& box = toRenderBox(inlineBox->renderer()); // Visual overflow only propagates if the box doesn't have a self-painting layer. This rectangle does not include // transforms or relative positioning (since those objects always have self-painting layers), but it does need to be adjusted // for writing-mode differences. - if (!box->hasSelfPaintingLayer()) { - LayoutRect childLogicalVisualOverflow = box->logicalVisualOverflowRectForPropagation(renderer()->style()); + if (!box.hasSelfPaintingLayer()) { + LayoutRect childLogicalVisualOverflow = box.logicalVisualOverflowRectForPropagation(renderer().style()); childLogicalVisualOverflow.move(inlineBox->logicalLeft(), inlineBox->logicalTop()); logicalVisualOverflow.unite(childLogicalVisualOverflow); } @@ -905,7 +921,7 @@ inline void InlineFlowBox::addReplacedChildOverflow(const InlineBox* inlineBox, // Layout overflow internal to the child box only propagates if the child box doesn't have overflow clip set. // Otherwise the child border box propagates as layout overflow. This rectangle must include transforms and relative positioning // and be adjusted for writing-mode differences. - LayoutRect childLogicalLayoutOverflow = box->logicalLayoutOverflowRectForPropagation(renderer()->style()); + LayoutRect childLogicalLayoutOverflow = box.logicalLayoutOverflowRectForPropagation(renderer().style()); childLogicalLayoutOverflow.move(inlineBox->logicalLeft(), inlineBox->logicalTop()); logicalLayoutOverflow.unite(childLogicalLayoutOverflow); } @@ -913,8 +929,13 @@ inline void InlineFlowBox::addReplacedChildOverflow(const InlineBox* inlineBox, void InlineFlowBox::computeOverflow(LayoutUnit lineTop, LayoutUnit lineBottom, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) { // If we know we have no overflow, we can just bail. - if (knownToHaveNoOverflow()) + if (knownToHaveNoOverflow()) { + ASSERT(!m_overflow); return; + } + + if (m_overflow) + m_overflow.clear(); // Visual overflow just includes overflow for stuff we need to repaint ourselves. Self-painting layers are ignored. // Layout overflow is used to determine scrolling extent, so it still includes child layers and also factors in @@ -924,20 +945,21 @@ void InlineFlowBox::computeOverflow(LayoutUnit lineTop, LayoutUnit lineBottom, G addBoxShadowVisualOverflow(logicalVisualOverflow); addBorderOutsetVisualOverflow(logicalVisualOverflow); + addOutlineVisualOverflow(logicalVisualOverflow); for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer()->isOutOfFlowPositioned()) + if (curr->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders don't affect calculations. - if (curr->renderer()->isText()) { + if (curr->renderer().isText()) { InlineTextBox* text = toInlineTextBox(curr); - RenderText* rt = toRenderText(text->renderer()); - if (rt->isBR()) + RenderText& rt = toRenderText(text->renderer()); + if (rt.isBR()) continue; LayoutRect textBoxOverflow(enclosingLayoutRect(text->logicalFrameRect())); addTextBoxVisualOverflow(text, textBoxDataMap, textBoxOverflow); logicalVisualOverflow.unite(textBoxOverflow); - } else if (curr->renderer()->isRenderInline()) { + } else if (curr->renderer().isRenderInline()) { InlineFlowBox* flow = toInlineFlowBox(curr); flow->computeOverflow(lineTop, lineBottom, textBoxDataMap); if (!flow->boxModelObject()->hasSelfPaintingLayer()) @@ -945,16 +967,16 @@ void InlineFlowBox::computeOverflow(LayoutUnit lineTop, LayoutUnit lineBottom, G LayoutRect childLayoutOverflow = flow->logicalLayoutOverflowRect(lineTop, lineBottom); childLayoutOverflow.move(flow->boxModelObject()->relativePositionLogicalOffset()); logicalLayoutOverflow.unite(childLayoutOverflow); - } else + } else { addReplacedChildOverflow(curr, logicalLayoutOverflow, logicalVisualOverflow); + } } setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, lineTop, lineBottom); } -void InlineFlowBox::setLayoutOverflow(const LayoutRect& rect, LayoutUnit lineTop, LayoutUnit lineBottom) +void InlineFlowBox::setLayoutOverflow(const LayoutRect& rect, const LayoutRect& frameBox) { - LayoutRect frameBox = enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom)); if (frameBox.contains(rect) || rect.isEmpty()) return; @@ -964,9 +986,8 @@ void InlineFlowBox::setLayoutOverflow(const LayoutRect& rect, LayoutUnit lineTop m_overflow->setLayoutOverflow(rect); } -void InlineFlowBox::setVisualOverflow(const LayoutRect& rect, LayoutUnit lineTop, LayoutUnit lineBottom) +void InlineFlowBox::setVisualOverflow(const LayoutRect& rect, const LayoutRect& frameBox) { - LayoutRect frameBox = enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom)); if (frameBox.contains(rect) || rect.isEmpty()) return; @@ -978,11 +999,13 @@ void InlineFlowBox::setVisualOverflow(const LayoutRect& rect, LayoutUnit lineTop void InlineFlowBox::setOverflowFromLogicalRects(const LayoutRect& logicalLayoutOverflow, const LayoutRect& logicalVisualOverflow, LayoutUnit lineTop, LayoutUnit lineBottom) { + LayoutRect frameBox = enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom)); + LayoutRect layoutOverflow(isHorizontal() ? logicalLayoutOverflow : logicalLayoutOverflow.transposedRect()); - setLayoutOverflow(layoutOverflow, lineTop, lineBottom); + setLayoutOverflow(layoutOverflow, frameBox); LayoutRect visualOverflow(isHorizontal() ? logicalVisualOverflow : logicalVisualOverflow.transposedRect()); - setVisualOverflow(visualOverflow, lineTop, lineBottom); + setVisualOverflow(visualOverflow, frameBox); } bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) @@ -997,11 +1020,11 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re // We need to account for culled inline parents of the hit-tested nodes, so that they may also get included in area-based hit-tests. RenderObject* culledParent = 0; for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) { - if (curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) { + if (curr->renderer().isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) { RenderObject* newParent = 0; // Culled parents are only relevant for area-based hit-tests, so ignore it in point-based ones. if (locationInContainer.isRectBasedTest()) { - newParent = curr->renderer()->parent(); + newParent = curr->renderer().parent(); if (newParent == renderer()) newParent = 0; } @@ -1018,7 +1041,7 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re culledParent = newParent; } if (curr->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom)) { - renderer()->updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); + renderer().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); return true; } } @@ -1038,13 +1061,13 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re LayoutUnit height = frameRect.height(); // Constrain our hit testing to the line top and bottom if necessary. - bool noQuirksMode = renderer()->document().inNoQuirksMode(); + bool noQuirksMode = renderer().document().inNoQuirksMode(); if (!noQuirksMode && !hasTextChildren() && !(descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) { - RootInlineBox* rootBox = root(); + RootInlineBox& rootBox = root(); LayoutUnit& top = isHorizontal() ? minY : minX; LayoutUnit& logicalHeight = isHorizontal() ? height : width; - LayoutUnit bottom = min(rootBox->lineBottom(), top + logicalHeight); - top = max(rootBox->lineTop(), top); + LayoutUnit bottom = min(rootBox.lineBottom(), top + logicalHeight); + top = max(rootBox.lineTop(), top); logicalHeight = bottom - top; } @@ -1054,8 +1077,8 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re rect.moveBy(accumulatedOffset); if (visibleToHitTestRequest(request) && locationInContainer.intersects(rect)) { - renderer()->updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset))); // Don't add in m_x or m_y here, we want coords in the containing block's space. - if (!result.addNodeToRectBasedTestResult(renderer()->node(), request, locationInContainer, rect)) + renderer().updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset))); // Don't add in m_x or m_y here, we want coords in the containing block's space. + if (!result.addNodeToRectBasedTestResult(renderer().node(), request, locationInContainer, rect)) return true; } @@ -1065,7 +1088,6 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re void InlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { LayoutRect overflowRect(visualOverflowRect(lineTop, lineBottom)); - overflowRect.inflate(renderer()->maximalOutlineSize(paintInfo.phase)); flipForWritingMode(overflowRect); overflowRect.moveBy(paintOffset); @@ -1076,16 +1098,16 @@ void InlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) { // Add ourselves to the paint info struct's list of inlines that need to paint their // outlines. - if (renderer()->style()->visibility() == VISIBLE && renderer()->hasOutline() && !isRootInlineBox()) { - RenderInline* inlineFlow = toRenderInline(renderer()); + if (renderer().style()->visibility() == VISIBLE && renderer().hasOutline() && !isRootInlineBox()) { + RenderInline& inlineFlow = toRenderInline(renderer()); RenderBlock* cb = 0; - bool containingBlockPaintsContinuationOutline = inlineFlow->continuation() || inlineFlow->isInlineElementContinuation(); + bool containingBlockPaintsContinuationOutline = inlineFlow.continuation() || inlineFlow.isInlineElementContinuation(); if (containingBlockPaintsContinuationOutline) { // FIXME: See https://bugs.webkit.org/show_bug.cgi?id=54690. We currently don't reconnect inline continuations // after a child removal. As a result, those merged inlines do not get seperated and hence not get enclosed by // anonymous blocks. In this case, it is better to bail out and paint it ourself. - RenderBlock* enclosingAnonymousBlock = renderer()->containingBlock(); + RenderBlock* enclosingAnonymousBlock = renderer().containingBlock(); if (!enclosingAnonymousBlock->isAnonymousBlock()) containingBlockPaintsContinuationOutline = false; else { @@ -1102,9 +1124,9 @@ void InlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, if (containingBlockPaintsContinuationOutline) { // Add ourselves to the containing block of the entire continuation so that it can // paint us atomically. - cb->addContinuationWithOutline(toRenderInline(renderer()->node()->renderer())); - } else if (!inlineFlow->isInlineElementContinuation()) { - paintInfo.outlineObjects()->add(inlineFlow); + cb->addContinuationWithOutline(toRenderInline(renderer().node()->renderer())); + } else if (!inlineFlow.isInlineElementContinuation()) { + paintInfo.outlineObjects()->add(&inlineFlow); } } } else if (paintInfo.phase == PaintPhaseMask) { @@ -1120,14 +1142,19 @@ void InlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, return; PaintPhase paintPhase = paintInfo.phase == PaintPhaseChildOutlines ? PaintPhaseOutline : paintInfo.phase; - PaintInfo childInfo(paintInfo); - childInfo.phase = paintPhase; - childInfo.updatePaintingRootForChildren(renderer()); // Paint our children. if (paintPhase != PaintPhaseSelfOutline) { + PaintInfo childInfo(paintInfo); + childInfo.phase = paintPhase; + + if (childInfo.paintingRoot && childInfo.paintingRoot->isDescendantOf(&renderer())) + childInfo.paintingRoot = 0; + else + childInfo.updatePaintingRootForChildren(&renderer()); + for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) + if (curr->renderer().isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) curr->paint(childInfo, paintOffset, lineTop, lineBottom); } } @@ -1146,17 +1173,17 @@ bool InlineFlowBox::boxShadowCanBeAppliedToBackground(const FillLayer& lastBackg // The checks here match how paintFillLayer() decides whether to clip (if it does, the shadow // would be clipped out, so it has to be drawn separately). StyleImage* image = lastBackgroundLayer.image(); - bool hasFillImage = image && image->canRender(renderer(), renderer()->style()->effectiveZoom()); - return (!hasFillImage && !renderer()->style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent(); + bool hasFillImage = image && image->canRender(renderer(), renderer().style()->effectiveZoom()); + return (!hasFillImage && !renderer().style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent(); } void InlineFlowBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect, CompositeOperator op) { StyleImage* img = fillLayer->image(); - bool hasFillImage = img && img->canRender(renderer(), renderer()->style()->effectiveZoom()); - if ((!hasFillImage && !renderer()->style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent()) + bool hasFillImage = img && img->canRender(renderer(), renderer().style()->effectiveZoom()); + if ((!hasFillImage && !renderer().style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent()) { boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, rect, BackgroundBleedNone, this, rect.size(), op); - else if (renderer()->style()->boxDecorationBreak() == DCLONE) { + } else if (renderer().style()->boxDecorationBreak() == DCLONE) { GraphicsContextStateSaver stateSaver(*paintInfo.context); paintInfo.context->clip(LayoutRect(rect.x(), rect.y(), width(), height())); boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, rect, BackgroundBleedNone, this, rect.size(), op); @@ -1169,7 +1196,7 @@ void InlineFlowBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, c // the previous line left off. LayoutUnit logicalOffsetOnLine = 0; LayoutUnit totalLogicalWidth; - if (renderer()->style()->direction() == LTR) { + if (renderer().style()->direction() == LTR) { for (InlineFlowBox* curr = prevLineBox(); curr; curr = curr->prevLineBox()) logicalOffsetOnLine += curr->logicalWidth(); totalLogicalWidth = logicalOffsetOnLine; @@ -1206,13 +1233,13 @@ void InlineFlowBox::paintBoxShadow(const PaintInfo& info, RenderStyle* s, Shadow void InlineFlowBox::constrainToLineTopAndBottomIfNeeded(LayoutRect& rect) const { - bool noQuirksMode = renderer()->document().inNoQuirksMode(); + bool noQuirksMode = renderer().document().inNoQuirksMode(); if (!noQuirksMode && !hasTextChildren() && !(descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) { - const RootInlineBox* rootBox = root(); + const RootInlineBox& rootBox = root(); LayoutUnit logicalTop = isHorizontal() ? rect.y() : rect.x(); LayoutUnit logicalHeight = isHorizontal() ? rect.height() : rect.width(); - LayoutUnit bottom = min(rootBox->lineBottom(), logicalTop + logicalHeight); - logicalTop = max(rootBox->lineTop(), logicalTop); + LayoutUnit bottom = min(rootBox.lineBottom(), logicalTop + logicalHeight); + logicalTop = max(rootBox.lineTop(), logicalTop); logicalHeight = bottom - logicalTop; if (isHorizontal()) { rect.setY(logicalTop); @@ -1227,7 +1254,7 @@ void InlineFlowBox::constrainToLineTopAndBottomIfNeeded(LayoutRect& rect) const static LayoutRect clipRectForNinePieceImageStrip(InlineFlowBox* box, const NinePieceImage& image, const LayoutRect& paintRect) { LayoutRect clipRect(paintRect); - RenderStyle* style = box->renderer()->style(); + RenderStyle* style = box->renderer().style(); LayoutBoxExtent outsets = style->imageOutsets(image); if (box->isHorizontal()) { clipRect.setY(paintRect.y() - outsets.top()); @@ -1253,7 +1280,7 @@ static LayoutRect clipRectForNinePieceImageStrip(InlineFlowBox* box, const NineP void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - if (!paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground) + if (!paintInfo.shouldPaintWithinRoot(&renderer()) || renderer().style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground) return; // Pixel snap background/border painting. @@ -1270,21 +1297,21 @@ 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(isFirstLineStyle()); - if ((!parent() && isFirstLineStyle() && 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)) paintBoxShadow(paintInfo, styleToUse, Normal, paintRect); - Color c = renderer()->resolveColor(styleToUse, CSSPropertyBackgroundColor); + Color c = renderer().resolveColor(styleToUse, CSSPropertyBackgroundColor); paintFillLayers(paintInfo, c, styleToUse->backgroundLayers(), paintRect); paintBoxShadow(paintInfo, styleToUse, Inset, paintRect); // :first-line cannot be used to put borders on a line. Always paint borders with our // non-first-line style. - if (parent() && renderer()->style()->hasBorder()) { - const NinePieceImage& borderImage = renderer()->style()->borderImage(); + if (parent() && renderer().style()->hasBorder()) { + const NinePieceImage& borderImage = renderer().style()->borderImage(); StyleImage* borderImageSource = borderImage.image(); bool hasBorderImage = borderImageSource && borderImageSource->canRender(renderer(), styleToUse->effectiveZoom()); if (hasBorderImage && !borderImageSource->isLoaded()) @@ -1293,7 +1320,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(isFirstLineStyle()), 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. @@ -1317,7 +1344,7 @@ void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& LayoutRect clipRect = clipRectForNinePieceImageStrip(this, borderImage, paintRect); GraphicsContextStateSaver stateSaver(*context); context->clip(clipRect); - boxModelObject()->paintBorder(paintInfo, LayoutRect(stripX, stripY, stripWidth, stripHeight), renderer()->style(isFirstLineStyle())); + boxModelObject()->paintBorder(paintInfo, LayoutRect(stripX, stripY, stripWidth, stripHeight), renderer().style(isFirstLineStyle())); } } } @@ -1325,7 +1352,7 @@ void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& void InlineFlowBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - if (!paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) + if (!paintInfo.shouldPaintWithinRoot(&renderer()) || renderer().style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) return; // Pixel snap mask painting. @@ -1338,16 +1365,16 @@ void InlineFlowBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffs flipForWritingMode(localRect); LayoutPoint adjustedPaintOffset = paintOffset + localRect.location(); - const NinePieceImage& maskNinePieceImage = renderer()->style()->maskBoxImage(); - StyleImage* maskBoxImage = renderer()->style()->maskBoxImage().image(); + const NinePieceImage& maskNinePieceImage = renderer().style()->maskBoxImage(); + StyleImage* maskBoxImage = renderer().style()->maskBoxImage().image(); // 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; + bool compositedMask = renderer().hasLayer() && boxModelObject()->layer()->hasCompositedMask(); + bool flattenCompositingLayers = renderer().view()->frameView() && renderer().view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers; CompositeOperator compositeOp = CompositeSourceOver; if (!compositedMask || flattenCompositingLayers) { - if ((maskBoxImage && renderer()->style()->maskLayers()->hasImage()) || renderer()->style()->maskLayers()->next()) + if ((maskBoxImage && renderer().style()->maskLayers()->hasImage()) || renderer().style()->maskLayers()->next()) pushTransparencyLayer = true; compositeOp = CompositeDestinationIn; @@ -1359,9 +1386,9 @@ void InlineFlowBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffs } LayoutRect paintRect = LayoutRect(adjustedPaintOffset, frameRect.size()); - paintFillLayers(paintInfo, Color(), renderer()->style()->maskLayers(), paintRect, compositeOp); + paintFillLayers(paintInfo, Color::transparent, renderer().style()->maskLayers(), paintRect, compositeOp); - bool hasBoxImage = maskBoxImage && maskBoxImage->canRender(renderer(), renderer()->style()->effectiveZoom()); + bool hasBoxImage = maskBoxImage && maskBoxImage->canRender(renderer(), renderer().style()->effectiveZoom()); if (!hasBoxImage || !maskBoxImage->isLoaded()) { if (pushTransparencyLayer) paintInfo.context->endLayer(); @@ -1371,7 +1398,7 @@ void InlineFlowBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffs // The simple case is where we are the only box for this object. In those // cases only a single call to draw is required. if (!prevLineBox() && !nextLineBox()) { - boxModelObject()->paintNinePieceImage(paintInfo.context, LayoutRect(adjustedPaintOffset, frameRect.size()), renderer()->style(), maskNinePieceImage, compositeOp); + boxModelObject()->paintNinePieceImage(paintInfo.context, LayoutRect(adjustedPaintOffset, frameRect.size()), renderer().style(), maskNinePieceImage, compositeOp); } else { // We have a mask image that spans multiple lines. // We need to adjust _tx and _ty by the width of all previous lines. @@ -1389,7 +1416,7 @@ void InlineFlowBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffs LayoutRect clipRect = clipRectForNinePieceImageStrip(this, maskNinePieceImage, paintRect); GraphicsContextStateSaver stateSaver(*paintInfo.context); paintInfo.context->clip(clipRect); - boxModelObject()->paintNinePieceImage(paintInfo.context, LayoutRect(stripX, stripY, stripWidth, stripHeight), renderer()->style(), maskNinePieceImage, compositeOp); + boxModelObject()->paintNinePieceImage(paintInfo.context, LayoutRect(stripX, stripY, stripWidth, stripHeight), renderer().style(), maskNinePieceImage, compositeOp); } if (pushTransparencyLayer) @@ -1466,19 +1493,19 @@ LayoutUnit InlineFlowBox::computeOverAnnotationAdjustment(LayoutUnit allowedPosi { LayoutUnit result = 0; for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer()->isOutOfFlowPositioned()) + if (curr->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders don't affect calculations. if (curr->isInlineFlowBox()) result = max(result, toInlineFlowBox(curr)->computeOverAnnotationAdjustment(allowedPosition)); - if (curr->renderer()->isReplaced() && curr->renderer()->isRubyRun() && curr->renderer()->style()->rubyPosition() == RubyPositionBefore) { - RenderRubyRun* rubyRun = toRenderRubyRun(curr->renderer()); - RenderRubyText* rubyText = rubyRun->rubyText(); + if (curr->renderer().isReplaced() && curr->renderer().isRubyRun() && curr->renderer().style()->rubyPosition() == RubyPositionBefore) { + RenderRubyRun& rubyRun = toRenderRubyRun(curr->renderer()); + RenderRubyText* rubyText = rubyRun.rubyText(); if (!rubyText) continue; - if (!rubyRun->style()->isFlippedLinesWritingMode()) { + if (!rubyRun.style()->isFlippedLinesWritingMode()) { LayoutUnit topOfFirstRubyTextLine = rubyText->logicalTop() + (rubyText->firstRootBox() ? rubyText->firstRootBox()->lineTop() : LayoutUnit()); if (topOfFirstRubyTextLine >= 0) continue; @@ -1494,7 +1521,7 @@ LayoutUnit InlineFlowBox::computeOverAnnotationAdjustment(LayoutUnit allowedPosi } if (curr->isInlineTextBox()) { - RenderStyle* style = curr->renderer()->style(isFirstLineStyle()); + RenderStyle* style = curr->renderer().style(isFirstLineStyle()); TextEmphasisPosition emphasisMarkPosition; if (style->textEmphasisMark() != TextEmphasisMarkNone && toInlineTextBox(curr)->getEmphasisMarkPosition(style, emphasisMarkPosition) && emphasisMarkPosition == TextEmphasisPositionOver) { if (!style->isFlippedLinesWritingMode()) { @@ -1514,19 +1541,19 @@ LayoutUnit InlineFlowBox::computeUnderAnnotationAdjustment(LayoutUnit allowedPos { LayoutUnit result = 0; for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer()->isOutOfFlowPositioned()) + if (curr->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders don't affect calculations. if (curr->isInlineFlowBox()) result = max(result, toInlineFlowBox(curr)->computeUnderAnnotationAdjustment(allowedPosition)); - if (curr->renderer()->isReplaced() && curr->renderer()->isRubyRun() && curr->renderer()->style()->rubyPosition() == RubyPositionAfter) { - RenderRubyRun* rubyRun = toRenderRubyRun(curr->renderer()); - RenderRubyText* rubyText = rubyRun->rubyText(); + if (curr->renderer().isReplaced() && curr->renderer().isRubyRun() && curr->renderer().style()->rubyPosition() == RubyPositionAfter) { + RenderRubyRun& rubyRun = toRenderRubyRun(curr->renderer()); + RenderRubyText* rubyText = rubyRun.rubyText(); if (!rubyText) continue; - if (rubyRun->style()->isFlippedLinesWritingMode()) { + if (rubyRun.style()->isFlippedLinesWritingMode()) { LayoutUnit topOfFirstRubyTextLine = rubyText->logicalTop() + (rubyText->firstRootBox() ? rubyText->firstRootBox()->lineTop() : LayoutUnit()); if (topOfFirstRubyTextLine >= 0) continue; @@ -1542,7 +1569,7 @@ LayoutUnit InlineFlowBox::computeUnderAnnotationAdjustment(LayoutUnit allowedPos } if (curr->isInlineTextBox()) { - RenderStyle* style = curr->renderer()->style(isFirstLineStyle()); + 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()); @@ -1573,7 +1600,7 @@ void InlineFlowBox::collectLeafBoxesInLogicalOrder(Vector<InlineBox*>& leafBoxes leafBoxesInLogicalOrder.append(leaf); } - if (renderer()->style()->rtlOrdering() == VisualOrder) + if (renderer().style()->rtlOrdering() == VisualOrder) return; // Reverse of reordering of the line (L2 according to Bidi spec): diff --git a/chromium/third_party/WebKit/Source/core/rendering/InlineFlowBox.h b/chromium/third_party/WebKit/Source/core/rendering/InlineFlowBox.h index 066098fdac8..795cab50a45 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/InlineFlowBox.h +++ b/chromium/third_party/WebKit/Source/core/rendering/InlineFlowBox.h @@ -40,7 +40,7 @@ typedef HashMap<const InlineTextBox*, pair<Vector<const SimpleFontData*>, GlyphO class InlineFlowBox : public InlineBox { public: - InlineFlowBox(RenderObject* obj) + InlineFlowBox(RenderObject& obj) : InlineBox(obj) , m_firstChild(0) , m_lastChild(0) @@ -52,6 +52,9 @@ public: , m_baselineType(AlphabeticBaseline) , m_hasAnnotationsBefore(false) , m_hasAnnotationsAfter(false) + , m_lineBreakBidiStatusEor(WTF::Unicode::LeftToRight) + , m_lineBreakBidiStatusLastStrong(WTF::Unicode::LeftToRight) + , m_lineBreakBidiStatusLast(WTF::Unicode::LeftToRight) #ifndef NDEBUG , m_hasBadChildList(false) #endif @@ -61,15 +64,15 @@ public: // an invisible marker exists. The side effect of having an invisible marker is that the quirks mode behavior of shrinking lines with no // text children must not apply. This change also means that gaps will exist between image bullet list items. Even when the list bullet // is an image, the line is still considered to be immune from the quirk. - m_hasTextChildren = obj->style()->display() == LIST_ITEM; + m_hasTextChildren = obj.style()->display() == LIST_ITEM; m_hasTextDescendants = m_hasTextChildren; } #ifndef NDEBUG virtual ~InlineFlowBox(); - virtual void showLineTreeAndMark(const InlineBox* = 0, const char* = 0, const InlineBox* = 0, const char* = 0, const RenderObject* = 0, int = 0) const; - virtual const char* boxName() const; + virtual void showLineTreeAndMark(const InlineBox* = 0, const char* = 0, const InlineBox* = 0, const char* = 0, const RenderObject* = 0, int = 0) const OVERRIDE; + virtual const char* boxName() const OVERRIDE; #endif InlineFlowBox* prevLineBox() const { return m_prevLineBox; } @@ -99,7 +102,7 @@ public: virtual void deleteLine() OVERRIDE FINAL; virtual void extractLine() OVERRIDE FINAL; virtual void attachLine() OVERRIDE FINAL; - virtual void adjustPosition(float dx, float dy); + virtual void adjustPosition(float dx, float dy) OVERRIDE; virtual void extractLineBoxFromRenderObject(); virtual void attachLineBoxToRenderObject(); @@ -114,7 +117,7 @@ public: void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver); void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver); void paintBoxShadow(const PaintInfo&, RenderStyle*, ShadowStyle, const LayoutRect&); - virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); + virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; bool boxShadowCanBeAppliedToBackground(const FillLayer&) const; @@ -140,13 +143,13 @@ public: { if (!includeLogicalLeftEdge()) return 0; - return isHorizontal() ? renderer()->style(isFirstLineStyle())->borderLeftWidth() : renderer()->style(isFirstLineStyle())->borderTopWidth(); + return isHorizontal() ? renderer().style(isFirstLineStyle())->borderLeftWidth() : renderer().style(isFirstLineStyle())->borderTopWidth(); } int borderLogicalRight() const { if (!includeLogicalRightEdge()) return 0; - return isHorizontal() ? renderer()->style(isFirstLineStyle())->borderRightWidth() : renderer()->style(isFirstLineStyle())->borderBottomWidth(); + return isHorizontal() ? renderer().style(isFirstLineStyle())->borderRightWidth() : renderer().style(isFirstLineStyle())->borderBottomWidth(); } int paddingLogicalLeft() const { @@ -197,9 +200,9 @@ public: void computeOverflow(LayoutUnit lineTop, LayoutUnit lineBottom, GlyphOverflowAndFallbackFontsMap&); - void removeChild(InlineBox* child); + void removeChild(InlineBox* child, MarkLineBoxes); - virtual RenderObject::SelectionState selectionState(); + virtual RenderObject::SelectionState selectionState() OVERRIDE; virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const OVERRIDE FINAL; virtual float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, float &truncatedWidth, bool&) OVERRIDE; @@ -244,7 +247,7 @@ public: LayoutRect logicalLayoutOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const { LayoutRect result = layoutOverflowRect(lineTop, lineBottom); - if (!renderer()->isHorizontalWritingMode()) + if (!renderer().isHorizontalWritingMode()) result = result.transposedRect(); return result; } @@ -270,25 +273,23 @@ public: LayoutRect logicalVisualOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const { LayoutRect result = visualOverflowRect(lineTop, lineBottom); - if (!renderer()->isHorizontalWritingMode()) + if (!renderer().isHorizontalWritingMode()) result = result.transposedRect(); return result; } void setOverflowFromLogicalRects(const LayoutRect& logicalLayoutOverflow, const LayoutRect& logicalVisualOverflow, LayoutUnit lineTop, LayoutUnit lineBottom); - void setLayoutOverflow(const LayoutRect&, LayoutUnit lineTop, LayoutUnit lineBottom); - void setVisualOverflow(const LayoutRect&, LayoutUnit lineTop, LayoutUnit lineBottom); FloatRect frameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const { if (isHorizontal()) - return FloatRect(m_topLeft.x(), lineTop, width(), lineBottom - lineTop); - return FloatRect(lineTop, m_topLeft.y(), lineBottom - lineTop, height()); + return FloatRect(m_topLeft.x(), lineTop.toFloat(), width(), (lineBottom - lineTop).toFloat()); + return FloatRect(lineTop.toFloat(), m_topLeft.y(), (lineBottom - lineTop).toFloat(), height()); } FloatRect logicalFrameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const { - return FloatRect(logicalLeft(), lineTop, logicalWidth(), lineBottom - lineTop); + return FloatRect(logicalLeft(), lineTop.toFloat(), logicalWidth(), (lineBottom - lineTop).toFloat()); } bool descendantsHaveSameLineHeightAndBaseline() const { return m_descendantsHaveSameLineHeightAndBaseline; } @@ -302,10 +303,14 @@ public: private: void addBoxShadowVisualOverflow(LayoutRect& logicalVisualOverflow); void addBorderOutsetVisualOverflow(LayoutRect& logicalVisualOverflow); + void addOutlineVisualOverflow(LayoutRect& logicalVisualOverflow); void addTextBoxVisualOverflow(InlineTextBox*, GlyphOverflowAndFallbackFontsMap&, LayoutRect& logicalVisualOverflow); void addReplacedChildOverflow(const InlineBox*, LayoutRect& logicalLayoutOverflow, LayoutRect& logicalVisualOverflow); void constrainToLineTopAndBottomIfNeeded(LayoutRect&) const; + void setLayoutOverflow(const LayoutRect&, const LayoutRect&); + void setVisualOverflow(const LayoutRect&, const LayoutRect&); + protected: OwnPtr<RenderOverflow> m_overflow; diff --git a/chromium/third_party/WebKit/Source/core/rendering/InlineIterator.h b/chromium/third_party/WebKit/Source/core/rendering/InlineIterator.h index c0c30d9ad8a..e0ecc103241 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/InlineIterator.h +++ b/chromium/third_party/WebKit/Source/core/rendering/InlineIterator.h @@ -25,6 +25,7 @@ #include "core/rendering/BidiRun.h" #include "core/rendering/RenderBlockFlow.h" +#include "core/rendering/RenderInline.h" #include "core/rendering/RenderText.h" #include "wtf/StdLibExtras.h" @@ -43,16 +44,16 @@ public: InlineIterator() : m_root(0) , m_obj(0) - , m_pos(0) , m_nextBreakablePosition(-1) + , m_pos(0) { } InlineIterator(RenderObject* root, RenderObject* o, unsigned p) : m_root(root) , m_obj(o) - , m_pos(p) , m_nextBreakablePosition(-1) + , m_pos(p) { } @@ -73,7 +74,11 @@ public: RenderObject* object() const { return m_obj; } void setObject(RenderObject* object) { m_obj = object; } + int nextBreakablePosition() const { return m_nextBreakablePosition; } + void setNextBreakablePosition(int position) { m_nextBreakablePosition = position; } + unsigned offset() const { return m_pos; } + void setOffset(unsigned position) { m_pos = position; } RenderObject* root() const { return m_root; } void fastIncrementInTextNode(); @@ -100,20 +105,18 @@ private: RenderObject* m_root; RenderObject* m_obj; -// FIXME: These should be private. -public: - unsigned m_pos; int m_nextBreakablePosition; + unsigned m_pos; }; inline bool operator==(const InlineIterator& it1, const InlineIterator& it2) { - return it1.m_pos == it2.m_pos && it1.object() == it2.object(); + return it1.offset() == it2.offset() && it1.object() == it2.object(); } inline bool operator!=(const InlineIterator& it1, const InlineIterator& it2) { - return it1.m_pos != it2.m_pos || it1.object() != it2.object(); + return it1.offset() != it2.offset() || it1.object() != it2.object(); } static inline WTF::Unicode::Direction embedCharFromDirection(TextDirection dir, EUnicodeBidi unicodeBidi) @@ -187,7 +190,7 @@ static bool isEmptyInline(RenderObject* object) if (!object->isRenderInline()) return false; - for (RenderObject* curr = object->firstChild(); curr; curr = curr->nextSibling()) { + for (RenderObject* curr = toRenderInline(object)->firstChild(); curr; curr = curr->nextSibling()) { if (curr->isFloatingOrOutOfFlowPositioned()) continue; if (curr->isText() && toRenderText(curr)->isAllCollapsibleWhitespace()) @@ -213,7 +216,7 @@ static inline RenderObject* bidiNextShared(RenderObject* root, RenderObject* cur while (current) { next = 0; if (!oldEndOfInline && !isIteratorTarget(current)) { - next = current->firstChild(); + next = current->slowFirstChild(); notifyObserverEnteredObject(observer, next); } @@ -280,7 +283,7 @@ static inline RenderObject* bidiNextIncludingEmptyInlines(RenderObject* root, Re return bidiNextShared(root, current, observer, IncludeEmptyInlines, endOfInlinePtr); } -static inline RenderObject* bidiFirstSkippingEmptyInlines(RenderObject* root, InlineBidiResolver* resolver = 0) +static inline RenderObject* bidiFirstSkippingEmptyInlines(RenderBlockFlow* root, InlineBidiResolver* resolver = 0) { RenderObject* o = root->firstChild(); if (!o) @@ -308,7 +311,7 @@ static inline RenderObject* bidiFirstSkippingEmptyInlines(RenderObject* root, In } // FIXME: This method needs to be renamed when bidiNext finds a good name. -static inline RenderObject* bidiFirstIncludingEmptyInlines(RenderObject* root) +static inline RenderObject* bidiFirstIncludingEmptyInlines(RenderBlock* root) { RenderObject* o = root->firstChild(); // If either there are no children to walk, or the first one is correct @@ -332,7 +335,7 @@ inline void InlineIterator::fastIncrementInTextNode() // it shouldn't use functions called bidiFirst and bidiNext. class InlineWalker { public: - InlineWalker(RenderObject* root) + InlineWalker(RenderBlock* root) : m_root(root) , m_current(0) , m_atEndOfInline(false) @@ -341,7 +344,7 @@ public: m_current = bidiFirstIncludingEmptyInlines(m_root); } - RenderObject* root() { return m_root; } + RenderBlock* root() { return m_root; } RenderObject* current() { return m_current; } bool atEndOfInline() { return m_atEndOfInline; } @@ -354,7 +357,7 @@ public: return m_current; } private: - RenderObject* m_root; + RenderBlock* m_root; RenderObject* m_current; bool m_atEndOfInline; }; @@ -442,13 +445,74 @@ inline bool InlineBidiResolver::isEndOfLine(const InlineIterator& end) { bool inEndOfLine = m_current == end || m_current.atEnd() || (inIsolate() && m_current.object() == end.object()); if (inIsolate() && inEndOfLine) { - m_current.moveTo(m_current.object(), end.m_pos, m_current.m_nextBreakablePosition); + m_current.moveTo(m_current.object(), end.offset(), m_current.nextBreakablePosition()); m_last = m_current; updateStatusLastFromCurrentDirection(WTF::Unicode::OtherNeutral); } return inEndOfLine; } +static inline bool isCollapsibleSpace(UChar character, RenderText* renderer) +{ + if (character == ' ' || character == '\t' || character == softHyphen) + return true; + if (character == '\n') + return !renderer->style()->preserveNewline(); + return false; +} + +template <typename CharacterType> +static inline int findFirstTrailingSpace(RenderText* lastText, const CharacterType* characters, int start, int stop) +{ + int firstSpace = stop; + while (firstSpace > start) { + UChar current = characters[firstSpace - 1]; + if (!isCollapsibleSpace(current, lastText)) + break; + firstSpace--; + } + + return firstSpace; +} + +template <> +inline int InlineBidiResolver::findFirstTrailingSpaceAtRun(BidiRun* run) +{ + ASSERT(run); + RenderObject* lastObject = run->m_object; + if (!lastObject->isText()) + return run->m_stop; + + RenderText* lastText = toRenderText(lastObject); + int firstSpace; + if (lastText->is8Bit()) + firstSpace = findFirstTrailingSpace(lastText, lastText->characters8(), run->start(), run->stop()); + else + firstSpace = findFirstTrailingSpace(lastText, lastText->characters16(), run->start(), run->stop()); + return firstSpace; +} + +template <> +inline BidiRun* InlineBidiResolver::addTrailingRun(int start, int stop, BidiRun* run, BidiContext* context, TextDirection direction) +{ + BidiRun* newTrailingRun = new BidiRun(start, stop, run->m_object, context, WTF::Unicode::OtherNeutral); + if (direction == LTR) + m_runs.addRun(newTrailingRun); + else + m_runs.prependRun(newTrailingRun); + + return newTrailingRun; +} + +template <> +inline bool InlineBidiResolver::needsToApplyL1Rule() +{ + if (!m_runs.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace() + || !m_runs.logicallyLastRun()->m_object->style()->autoWrap()) + return false; + return true; +} + static inline bool isIsolatedInline(RenderObject* object) { ASSERT(object); @@ -569,18 +633,18 @@ static void adjustMidpointsAndAppendRunsForObjectIfNeeded(RenderObject* obj, uns return; LineMidpointState& lineMidpointState = resolver.midpointState(); - bool haveNextMidpoint = (lineMidpointState.currentMidpoint < lineMidpointState.numMidpoints); + bool haveNextMidpoint = (lineMidpointState.currentMidpoint() < lineMidpointState.numMidpoints()); InlineIterator nextMidpoint; if (haveNextMidpoint) - nextMidpoint = lineMidpointState.midpoints[lineMidpointState.currentMidpoint]; - if (lineMidpointState.betweenMidpoints) { + nextMidpoint = lineMidpointState.midpoints()[lineMidpointState.currentMidpoint()]; + if (lineMidpointState.betweenMidpoints()) { if (!(haveNextMidpoint && nextMidpoint.object() == obj)) return; // This is a new start point. Stop ignoring objects and // adjust our start. - lineMidpointState.betweenMidpoints = false; - start = nextMidpoint.m_pos; - lineMidpointState.currentMidpoint++; + lineMidpointState.setBetweenMidpoints(false); + start = nextMidpoint.offset(); + lineMidpointState.incrementCurrentMidpoint(); if (start < end) return adjustMidpointsAndAppendRunsForObjectIfNeeded(obj, start, end, resolver, behavior, tracker); } else { @@ -591,13 +655,13 @@ static void adjustMidpointsAndAppendRunsForObjectIfNeeded(RenderObject* obj, uns // An end midpoint has been encountered within our object. We // need to go ahead and append a run with our endpoint. - if (nextMidpoint.m_pos + 1 <= end) { - lineMidpointState.betweenMidpoints = true; - lineMidpointState.currentMidpoint++; - if (nextMidpoint.m_pos != UINT_MAX) { // UINT_MAX means stop at the object and don't nclude any of it. - if (nextMidpoint.m_pos + 1 > start) - appendRunObjectIfNecessary(obj, start, nextMidpoint.m_pos + 1, resolver, behavior, tracker); - return adjustMidpointsAndAppendRunsForObjectIfNeeded(obj, nextMidpoint.m_pos + 1, end, resolver, behavior, tracker); + if (nextMidpoint.offset() + 1 <= end) { + lineMidpointState.setBetweenMidpoints(true); + lineMidpointState.incrementCurrentMidpoint(); + if (nextMidpoint.offset() != UINT_MAX) { // UINT_MAX means stop at the object and don't nclude any of it. + if (nextMidpoint.offset() + 1 > start) + appendRunObjectIfNecessary(obj, start, nextMidpoint.offset() + 1, resolver, behavior, tracker); + return adjustMidpointsAndAppendRunsForObjectIfNeeded(obj, nextMidpoint.offset() + 1, end, resolver, behavior, tracker); } } else { appendRunObjectIfNecessary(obj, start, end, resolver, behavior, tracker); @@ -619,7 +683,7 @@ inline void InlineBidiResolver::appendRun() // Initialize our state depending on if we're starting in the middle of such an inline. // FIXME: Could this initialize from this->inIsolate() instead of walking up the render tree? IsolateTracker isolateTracker(numberOfIsolateAncestors(m_sor)); - int start = m_sor.m_pos; + int start = m_sor.offset(); RenderObject* obj = m_sor.object(); while (obj && obj != m_eor.object() && obj != m_endOfRunAtEndOfLine.object()) { if (isolateTracker.inIsolate()) @@ -630,12 +694,12 @@ inline void InlineBidiResolver::appendRun() start = 0; obj = bidiNextSkippingEmptyInlines(m_sor.root(), obj, &isolateTracker); } - bool isEndOfLine = obj == m_endOfLine.object() && !m_endOfLine.m_pos; + bool isEndOfLine = obj == m_endOfLine.object() && !m_endOfLine.offset(); if (obj && !isEndOfLine) { - unsigned pos = obj == m_eor.object() ? m_eor.m_pos : INT_MAX; - if (obj == m_endOfRunAtEndOfLine.object() && m_endOfRunAtEndOfLine.m_pos <= pos) { + unsigned pos = obj == m_eor.object() ? m_eor.offset() : INT_MAX; + if (obj == m_endOfRunAtEndOfLine.object() && m_endOfRunAtEndOfLine.offset() <= pos) { m_reachedEndOfLine = true; - pos = m_endOfRunAtEndOfLine.m_pos; + pos = m_endOfRunAtEndOfLine.offset(); } // It's OK to add runs for zero-length RenderObjects, just don't make the run larger than it should be int end = obj->length() ? pos + 1 : 0; diff --git a/chromium/third_party/WebKit/Source/core/rendering/InlineTextBox.cpp b/chromium/third_party/WebKit/Source/core/rendering/InlineTextBox.cpp index 60a35deccf1..af997333d2d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/InlineTextBox.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/InlineTextBox.cpp @@ -27,9 +27,11 @@ #include "core/dom/DocumentMarkerController.h" #include "core/dom/RenderedDocumentMarker.h" #include "core/dom/Text.h" +#include "core/editing/CompositionUnderline.h" +#include "core/editing/CompositionUnderlineRangeFilter.h" #include "core/editing/Editor.h" #include "core/editing/InputMethodController.h" -#include "core/frame/Frame.h" +#include "core/frame/LocalFrame.h" #include "core/page/Page.h" #include "core/frame/Settings.h" #include "core/rendering/AbstractInlineTextBox.h" @@ -45,13 +47,16 @@ #include "core/rendering/style/ShadowList.h" #include "core/rendering/svg/SVGTextRunRenderingContext.h" #include "platform/fonts/FontCache.h" +#include "platform/fonts/GlyphBuffer.h" #include "platform/fonts/WidthIterator.h" -#include "platform/graphics/DrawLooper.h" +#include "platform/graphics/DrawLooperBuilder.h" #include "platform/graphics/GraphicsContextStateSaver.h" #include "wtf/Vector.h" #include "wtf/text/CString.h" #include "wtf/text/StringBuilder.h" +#include <algorithm> + using namespace std; namespace WebCore { @@ -78,13 +83,11 @@ void InlineTextBox::destroy() InlineBox::destroy(); } -void InlineTextBox::markDirty(bool dirty) +void InlineTextBox::markDirty() { - if (dirty) { - m_len = 0; - m_start = 0; - } - InlineBox::markDirty(dirty); + m_len = 0; + m_start = 0; + InlineBox::markDirty(); } LayoutRect InlineTextBox::logicalOverflowRect() const @@ -106,35 +109,35 @@ int InlineTextBox::baselinePosition(FontBaseline baselineType) const { if (!isText() || !parent()) return 0; - if (parent()->renderer() == renderer()->parent()) + if (parent()->renderer() == renderer().parent()) return parent()->baselinePosition(baselineType); - return toRenderBoxModelObject(renderer()->parent())->baselinePosition(baselineType, isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); + return toRenderBoxModelObject(renderer().parent())->baselinePosition(baselineType, isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); } LayoutUnit InlineTextBox::lineHeight() const { - if (!isText() || !renderer()->parent()) + if (!isText() || !renderer().parent()) return 0; - if (m_renderer->isBR()) - return toRenderBR(m_renderer)->lineHeight(isFirstLineStyle()); - if (parent()->renderer() == renderer()->parent()) + if (renderer().isBR()) + return toRenderBR(renderer()).lineHeight(isFirstLineStyle()); + if (parent()->renderer() == renderer().parent()) return parent()->lineHeight(); - return toRenderBoxModelObject(renderer()->parent())->lineHeight(isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); + return toRenderBoxModelObject(renderer().parent())->lineHeight(isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); } LayoutUnit InlineTextBox::selectionTop() { - return root()->selectionTop(); + return root().selectionTop(); } LayoutUnit InlineTextBox::selectionBottom() { - return root()->selectionBottom(); + return root().selectionBottom(); } LayoutUnit InlineTextBox::selectionHeight() { - return root()->selectionHeight(); + return root().selectionHeight(); } bool InlineTextBox::isSelected(int startPos, int endPos) const @@ -148,16 +151,16 @@ bool InlineTextBox::isSelected(int startPos, int endPos) const RenderObject::SelectionState InlineTextBox::selectionState() { - RenderObject::SelectionState state = renderer()->selectionState(); + RenderObject::SelectionState state = renderer().selectionState(); if (state == RenderObject::SelectionStart || state == RenderObject::SelectionEnd || state == RenderObject::SelectionBoth) { int startPos, endPos; - renderer()->selectionStartEnd(startPos, endPos); + renderer().selectionStartEnd(startPos, endPos); // The position after a hard line break is considered to be past its end. // See the corresponding code in InlineTextBox::isSelected. int lastSelectable = start() + len() - (isLineBreak() ? 1 : 0); // FIXME: Remove -webkit-line-break: LineBreakAfterWhiteSpace. - int endOfLineAdjustmentForCSSLineBreak = renderer()->style()->lineBreak() == LineBreakAfterWhiteSpace ? -1 : 0; + int endOfLineAdjustmentForCSSLineBreak = renderer().style()->lineBreak() == LineBreakAfterWhiteSpace ? -1 : 0; bool start = (state != RenderObject::SelectionEnd && startPos >= m_start && startPos <= m_start + m_len + endOfLineAdjustmentForCSSLineBreak); bool end = (state != RenderObject::SelectionStart && endPos > m_start && endPos <= lastSelectable); if (start && end) @@ -174,8 +177,8 @@ RenderObject::SelectionState InlineTextBox::selectionState() } // If there are ellipsis following, make sure their selection is updated. - if (m_truncation != cNoTruncation && root()->ellipsisBox()) { - EllipsisBox* ellipsis = root()->ellipsisBox(); + if (m_truncation != cNoTruncation && root().ellipsisBox()) { + EllipsisBox* ellipsis = root().ellipsisBox(); if (state != RenderObject::SelectionNone) { int start, end; selectionStartEnd(start, end); @@ -202,24 +205,21 @@ LayoutRect InlineTextBox::localSelectionRect(int startPos, int endPos) FontCachePurgePreventer fontCachePurgePreventer; - RenderText* textObj = textRenderer(); LayoutUnit selTop = selectionTop(); LayoutUnit selHeight = selectionHeight(); - RenderStyle* styleToUse = textObj->style(isFirstLineStyle()); + RenderStyle* styleToUse = textRenderer().style(isFirstLineStyle()); const Font& font = styleToUse->font(); StringBuilder charactersWithHyphen; bool respectHyphen = ePos == m_len && hasHyphen(); TextRun textRun = constructTextRun(styleToUse, font, respectHyphen ? &charactersWithHyphen : 0); - if (respectHyphen) - endPos = textRun.length(); - FloatPoint startingPoint = FloatPoint(logicalLeft(), selTop); + FloatPoint startingPoint = FloatPoint(logicalLeft(), selTop.toFloat()); LayoutRect r; if (sPos || ePos != static_cast<int>(m_len)) r = enclosingIntRect(font.selectionRectForText(textRun, startingPoint, selHeight, sPos, ePos)); else // Avoid computing the font width when the entire line box is selected as an optimization. - r = enclosingIntRect(FloatRect(startingPoint, FloatSize(m_logicalWidth, selHeight))); + r = enclosingIntRect(FloatRect(startingPoint, FloatSize(m_logicalWidth, selHeight.toFloat()))); LayoutUnit logicalWidth = r.width(); if (r.x() > logicalRight()) @@ -236,7 +236,7 @@ LayoutRect InlineTextBox::localSelectionRect(int startPos, int endPos) void InlineTextBox::deleteLine() { - toRenderText(renderer())->removeTextBox(this); + toRenderText(renderer()).removeTextBox(this); destroy(); } @@ -245,7 +245,7 @@ void InlineTextBox::extractLine() if (extracted()) return; - toRenderText(renderer())->extractTextBox(this); + toRenderText(renderer()).extractTextBox(this); } void InlineTextBox::attachLine() @@ -253,7 +253,7 @@ void InlineTextBox::attachLine() if (!extracted()) return; - toRenderText(renderer())->attachTextBox(this); + toRenderText(renderer()).attachTextBox(this); } float InlineTextBox::placeEllipsisBox(bool flowIsLTR, float visibleLeftEdge, float visibleRightEdge, float ellipsisWidth, float &truncatedWidth, bool& foundBox) @@ -307,7 +307,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(), isFirstLineStyle()); + float widthOfVisibleText = toRenderText(renderer()).width(m_start, offset, textPos(), flowIsLTR ? LTR : RTL, isFirstLineStyle()); // The ellipsis needs to be placed just after the last visible character. // Where "after" is defined by the flow directionality, not the inline @@ -369,7 +369,7 @@ void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, con bool InlineTextBox::isLineBreak() const { - return renderer()->isBR() || (renderer()->style()->preserveNewline() && len() == 1 && (*textRenderer()->text().impl())[start()] == '\n'); + return renderer().isBR() || (renderer().style()->preserveNewline() && len() == 1 && (*textRenderer().text().impl())[start()] == '\n'); } bool InlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) @@ -381,15 +381,15 @@ bool InlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re boxOrigin.moveBy(accumulatedOffset); FloatRect rect(boxOrigin, size()); if (m_truncation != cFullTruncation && visibleToHitTestRequest(request) && locationInContainer.intersects(rect)) { - renderer()->updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset))); - if (!result.addNodeToRectBasedTestResult(renderer()->node(), request, locationInContainer, rect)) + renderer().updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset))); + if (!result.addNodeToRectBasedTestResult(renderer().node(), request, locationInContainer, rect)) return true; } return false; } static void paintTextWithShadows(GraphicsContext* context, - const RenderObject* renderer, const Font& font, const TextRun& textRun, + const RenderObject& renderer, const Font& font, const TextRun& textRun, const AtomicString& emphasisMark, int emphasisMarkOffset, int startOffset, int endOffset, int truncationPoint, const FloatPoint& textOrigin, const FloatRect& boxRect, @@ -399,17 +399,17 @@ static void paintTextWithShadows(GraphicsContext* context, bool hasShadow = shadowList && !context->printing(); if (hasShadow) { - DrawLooper drawLooper; + OwnPtr<DrawLooperBuilder> drawLooperBuilder = DrawLooperBuilder::create(); for (size_t i = shadowList->shadows().size(); i--; ) { const ShadowData& shadow = shadowList->shadows()[i]; - int shadowX = horizontal ? shadow.x() : shadow.y(); - int shadowY = horizontal ? shadow.y() : -shadow.x(); + float shadowX = horizontal ? shadow.x() : shadow.y(); + float shadowY = horizontal ? shadow.y() : -shadow.x(); FloatSize offset(shadowX, shadowY); - drawLooper.addShadow(offset, shadow.blur(), renderer->resolveColor(shadow.color()), - DrawLooper::ShadowRespectsTransforms, DrawLooper::ShadowIgnoresAlpha); + drawLooperBuilder->addShadow(offset, shadow.blur(), shadow.color(), + DrawLooperBuilder::ShadowRespectsTransforms, DrawLooperBuilder::ShadowIgnoresAlpha); } - drawLooper.addUnmodifiedContent(); - context->setDrawLooper(drawLooper); + drawLooperBuilder->addUnmodifiedContent(); + context->setDrawLooper(drawLooperBuilder.release()); } TextRunPaintInfo textRunPaintInfo(textRun); @@ -454,7 +454,7 @@ bool InlineTextBox::getEmphasisMarkPosition(RenderStyle* style, TextEmphasisPosi if (emphasisPosition == TextEmphasisPositionUnder) return true; // Ruby text is always over, so it cannot suppress emphasis marks under. - RenderBlock* containingBlock = renderer()->containingBlock(); + RenderBlock* containingBlock = renderer().containingBlock(); if (!containingBlock->isRubyBase()) return true; // This text is not inside a ruby base, so it does not have ruby text over it. @@ -469,8 +469,8 @@ bool InlineTextBox::getEmphasisMarkPosition(RenderStyle* style, TextEmphasisPosi void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /*lineTop*/, LayoutUnit /*lineBottom*/) { - if (isLineBreak() || !paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE || - m_truncation == cFullTruncation || paintInfo.phase == PaintPhaseOutline || !m_len) + if (isLineBreak() || !paintInfo.shouldPaintWithinRoot(&renderer()) || renderer().style()->visibility() != VISIBLE + || m_truncation == cFullTruncation || paintInfo.phase == PaintPhaseOutline || !m_len) return; ASSERT(paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines); @@ -483,12 +483,18 @@ 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 = roundedIntPoint(paintOffset); + // When subpixel font scaling is enabled text runs are positioned at + // subpixel boundaries on the x-axis and thus there is no reason to + // snap the x value. We still round the y-axis to ensure consistent + // line heights. + LayoutPoint adjustedPaintOffset = RuntimeEnabledFeatures::subpixelFontScalingEnabled() + ? LayoutPoint(paintOffset.x(), paintOffset.y().round()) + : roundedIntPoint(paintOffset); if (logicalStart >= paintEnd || logicalStart + logicalExtent <= paintStart) return; - bool isPrinting = textRenderer()->document().printing(); + bool isPrinting = textRenderer().document().printing(); // Determine whether or not we're selected. bool haveSelection = !isPrinting && paintInfo.phase != PaintPhaseTextClip && selectionState() != RenderObject::SelectionNone; @@ -497,7 +503,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, return; if (m_truncation != cNoTruncation) { - if (renderer()->containingBlock()->style()->isLeftToRightDirection() != isLeftToRightDirection()) { + if (renderer().containingBlock()->style()->isLeftToRightDirection() != isLeftToRightDirection()) { // Make the visible fragment of text hug the edge closest to the rest of the run by moving the origin // at which we start drawing text. // e.g. In the case of LTR text truncated in an RTL Context, the correct behavior is: @@ -506,7 +512,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(), isFirstLineStyle()); + LayoutUnit widthOfVisibleText = toRenderText(renderer()).width(m_start, m_truncation, textPos(), isLeftToRightDirection() ? LTR : RTL, 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,24 +522,24 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, GraphicsContext* context = paintInfo.context; - RenderObject* rendererToUse = renderer(); - RenderStyle* styleToUse = rendererToUse->style(isFirstLineStyle()); + RenderObject& rendererToUse = renderer(); + RenderStyle* styleToUse = rendererToUse.style(isFirstLineStyle()); adjustedPaintOffset.move(0, styleToUse->isHorizontalWritingMode() ? 0 : -logicalHeight()); FloatPoint boxOrigin = locationIncludingFlipping(); - boxOrigin.move(adjustedPaintOffset.x(), adjustedPaintOffset.y()); + boxOrigin.move(adjustedPaintOffset.x().toFloat(), adjustedPaintOffset.y().toFloat()); FloatRect boxRect(boxOrigin, LayoutSize(logicalWidth(), logicalHeight())); - RenderCombineText* combinedText = styleToUse->hasTextCombine() && textRenderer()->isCombineText() && toRenderCombineText(textRenderer())->isCombined() ? toRenderCombineText(textRenderer()) : 0; + RenderCombineText* combinedText = styleToUse->hasTextCombine() && textRenderer().isCombineText() && toRenderCombineText(textRenderer()).isCombined() ? &toRenderCombineText(textRenderer()) : 0; bool shouldRotate = !isHorizontal() && !combinedText; if (shouldRotate) context->concatCTM(rotation(boxRect, Clockwise)); // Determine whether or not we have composition underlines to draw. - bool containsComposition = renderer()->node() && renderer()->frame()->inputMethodController().compositionNode() == renderer()->node(); - bool useCustomUnderlines = containsComposition && renderer()->frame()->inputMethodController().compositionUsesCustomUnderlines(); + bool containsComposition = renderer().node() && renderer().frame()->inputMethodController().compositionNode() == renderer().node(); + bool useCustomUnderlines = containsComposition && renderer().frame()->inputMethodController().compositionUsesCustomUnderlines(); // Determine the text colors and selection colors. Color textFillColor; @@ -549,13 +555,13 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, textStrokeColor = Color::black; emphasisMarkColor = Color::black; } else { - textFillColor = rendererToUse->resolveColor(styleToUse, CSSPropertyWebkitTextFillColor); + textFillColor = rendererToUse.resolveColor(styleToUse, CSSPropertyWebkitTextFillColor); bool forceBackgroundToWhite = false; if (isPrinting) { if (styleToUse->printColorAdjust() == PrintColorAdjustEconomy) forceBackgroundToWhite = true; - if (textRenderer()->document().settings() && textRenderer()->document().settings()->shouldPrintBackgrounds()) + if (textRenderer().document().settings() && textRenderer().document().settings()->shouldPrintBackgrounds()) forceBackgroundToWhite = false; } @@ -563,13 +569,13 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, if (forceBackgroundToWhite) textFillColor = correctedTextColor(textFillColor, Color::white); - textStrokeColor = rendererToUse->resolveColor(styleToUse, CSSPropertyWebkitTextStrokeColor); + textStrokeColor = rendererToUse.resolveColor(styleToUse, CSSPropertyWebkitTextStrokeColor); // Make the text stroke color legible against a white background if (forceBackgroundToWhite) textStrokeColor = correctedTextColor(textStrokeColor, Color::white); - emphasisMarkColor = rendererToUse->resolveColor(styleToUse, CSSPropertyWebkitTextEmphasisColor); + emphasisMarkColor = rendererToUse.resolveColor(styleToUse, CSSPropertyWebkitTextEmphasisColor); // Make the text stroke color legible against a white background if (forceBackgroundToWhite) @@ -586,21 +592,21 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, const ShadowList* selectionShadow = textShadow; if (haveSelection) { // Check foreground color first. - Color foreground = paintInfo.forceBlackText() ? Color::black : renderer()->selectionForegroundColor(); - if (foreground.isValid() && foreground != selectionFillColor && foreground != Color::transparent) { + Color foreground = paintInfo.forceBlackText() ? Color::black : renderer().selectionForegroundColor(); + if (foreground != selectionFillColor) { if (!paintSelectedTextOnly) paintSelectedTextSeparately = true; selectionFillColor = foreground; } - Color emphasisMarkForeground = paintInfo.forceBlackText() ? Color::black : renderer()->selectionEmphasisMarkColor(); - if (emphasisMarkForeground.isValid() && emphasisMarkForeground != selectionEmphasisMarkColor) { + Color emphasisMarkForeground = paintInfo.forceBlackText() ? Color::black : renderer().selectionEmphasisMarkColor(); + if (emphasisMarkForeground != selectionEmphasisMarkColor) { if (!paintSelectedTextOnly) paintSelectedTextSeparately = true; selectionEmphasisMarkColor = emphasisMarkForeground; } - if (RenderStyle* pseudoStyle = renderer()->getCachedPseudoStyle(SELECTION)) { + if (RenderStyle* pseudoStyle = renderer().getCachedPseudoStyle(SELECTION)) { // Text shadows are disabled when printing. http://crbug.com/258321 const ShadowList* shadow = (context->printing() || paintInfo.forceBlackText()) ? 0 : pseudoStyle->textShadow(); if (shadow != selectionShadow) { @@ -616,7 +622,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, selectionStrokeWidth = strokeWidth; } - Color stroke = paintInfo.forceBlackText() ? Color::black : rendererToUse->resolveColor(pseudoStyle, CSSPropertyWebkitTextStrokeColor); + Color stroke = paintInfo.forceBlackText() ? Color::black : rendererToUse.resolveColor(pseudoStyle, CSSPropertyWebkitTextStrokeColor); if (stroke != selectionStrokeColor) { if (!paintSelectedTextOnly) paintSelectedTextSeparately = true; @@ -634,13 +640,10 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, combinedText->adjustTextOrigin(textOrigin, boxRect); // 1. Paint backgrounds behind text if needed. Examples of such backgrounds include selection - // and composition underlines. + // and composition highlights. if (paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseTextClip && !isPrinting) { - - if (containsComposition && !useCustomUnderlines) { - paintCompositionBackground(context, boxOrigin, styleToUse, font, - renderer()->frame()->inputMethodController().compositionStart(), - renderer()->frame()->inputMethodController().compositionEnd()); + if (containsComposition) { + paintCompositionBackgrounds(context, boxOrigin, styleToUse, font, useCustomUnderlines); } paintDocumentMarkers(context, boxOrigin, styleToUse, font, true); @@ -654,10 +657,10 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, int maximumLength; StringView string; if (!combinedText) { - string = textRenderer()->text().createView(); + string = textRenderer().text().createView(); if (static_cast<unsigned>(length) != string.length() || m_start) string.narrow(m_start, length); - maximumLength = textRenderer()->textLength() - m_start; + maximumLength = textRenderer().textLength() - m_start; } else { combinedText->getStringToRender(m_start, string, length); maximumLength = length; @@ -708,12 +711,19 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, if (combinedText) context->concatCTM(rotation(boxRect, Clockwise)); - if (!paintSelectedTextSeparately || ePos <= sPos) { - // FIXME: Truncate right-to-left text correctly. - paintTextWithShadows(context, rendererToUse, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, 0, length, length, emphasisMarkTextOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal()); - } else { - paintTextWithShadows(context, rendererToUse, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, ePos, sPos, length, emphasisMarkTextOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal()); + int startOffset = 0; + int endOffset = length; + int paintRunLength = length; + if (combinedText) { + startOffset = 0; + endOffset = objectReplacementCharacterTextRun.length(); + paintRunLength = endOffset; + } else if (paintSelectedTextSeparately && ePos > sPos) { + startOffset = ePos; + endOffset = sPos; } + // FIXME: Truncate right-to-left text correctly. + paintTextWithShadows(context, rendererToUse, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, startOffset, endOffset, paintRunLength, emphasisMarkTextOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal()); if (combinedText) context->concatCTM(rotation(boxRect, Counterclockwise)); @@ -735,7 +745,10 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, if (combinedText) context->concatCTM(rotation(boxRect, Clockwise)); - paintTextWithShadows(context, rendererToUse, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, sPos, ePos, length, emphasisMarkTextOrigin, boxRect, selectionShadow, selectionStrokeWidth > 0, isHorizontal()); + int startOffset = combinedText ? 0 : sPos; + int endOffset = combinedText ? objectReplacementCharacterTextRun.length() : ePos; + int paintRunLength = combinedText ? endOffset : length; + paintTextWithShadows(context, rendererToUse, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, startOffset, endOffset, paintRunLength, emphasisMarkTextOrigin, boxRect, selectionShadow, selectionStrokeWidth > 0, isHorizontal()); if (combinedText) context->concatCTM(rotation(boxRect, Counterclockwise)); @@ -748,7 +761,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth); if (combinedText) context->concatCTM(rotation(boxRect, Clockwise)); - paintDecoration(context, boxOrigin, textDecorations, styleToUse->textDecorationStyle(), textShadow); + paintDecoration(context, boxOrigin, textDecorations, textShadow); if (combinedText) context->concatCTM(rotation(boxRect, Counterclockwise)); } @@ -756,28 +769,14 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, if (paintInfo.phase == PaintPhaseForeground) { paintDocumentMarkers(context, boxOrigin, styleToUse, font, false); + // Paint custom underlines for compositions. if (useCustomUnderlines) { - const Vector<CompositionUnderline>& underlines = renderer()->frame()->inputMethodController().customCompositionUnderlines(); - size_t numUnderlines = underlines.size(); - - for (size_t index = 0; index < numUnderlines; ++index) { - const CompositionUnderline& underline = underlines[index]; - - if (underline.endOffset <= start()) - // underline is completely before this run. This might be an underline that sits - // before the first run we draw, or underlines that were within runs we skipped - // due to truncation. + const Vector<CompositionUnderline>& underlines = renderer().frame()->inputMethodController().customCompositionUnderlines(); + CompositionUnderlineRangeFilter filter(underlines, start(), end()); + for (CompositionUnderlineRangeFilter::ConstIterator it = filter.begin(); it != filter.end(); ++it) { + if (it->color == Color::transparent) continue; - - if (underline.startOffset <= end()) { - // underline intersects this run. Paint it. - paintCompositionUnderline(context, boxOrigin, underline); - if (underline.endOffset > end() + 1) - // underline also runs into the next run. Bail now, no more marker advancement. - break; - } else - // underline is completely after this run, bail. A later run will paint it. - break; + paintCompositionUnderline(context, boxOrigin, *it); } } } @@ -789,14 +788,14 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, void InlineTextBox::selectionStartEnd(int& sPos, int& ePos) { int startPos, endPos; - if (renderer()->selectionState() == RenderObject::SelectionInside) { + if (renderer().selectionState() == RenderObject::SelectionInside) { startPos = 0; - endPos = textRenderer()->textLength(); + endPos = textRenderer().textLength(); } else { - textRenderer()->selectionStartEnd(startPos, endPos); - if (renderer()->selectionState() == RenderObject::SelectionStart) - endPos = textRenderer()->textLength(); - else if (renderer()->selectionState() == RenderObject::SelectionEnd) + textRenderer().selectionStartEnd(startPos, endPos); + if (renderer().selectionState() == RenderObject::SelectionStart) + endPos = textRenderer().textLength(); + else if (renderer().selectionState() == RenderObject::SelectionEnd) startPos = 0; } @@ -822,8 +821,8 @@ void InlineTextBox::paintSelection(GraphicsContext* context, const FloatPoint& b if (sPos >= ePos) return; - Color c = renderer()->selectionBackgroundColor(); - if (!c.isValid() || !c.alpha()) + Color c = renderer().selectionBackgroundColor(); + if (!c.alpha()) return; // If the text color ends up being the same as the selection background, invert the selection @@ -837,21 +836,21 @@ void InlineTextBox::paintSelection(GraphicsContext* context, const FloatPoint& b // If the text is truncated, let the thing being painted in the truncation // draw its own highlight. int length = m_truncation != cNoTruncation ? m_truncation : m_len; - StringView string = textRenderer()->text().createView(); + StringView string = textRenderer().text().createView(); if (string.length() != static_cast<unsigned>(length) || m_start) string.narrow(m_start, length); StringBuilder charactersWithHyphen; bool respectHyphen = ePos == length && hasHyphen(); - TextRun textRun = constructTextRun(style, font, string, textRenderer()->textLength() - m_start, respectHyphen ? &charactersWithHyphen : 0); + TextRun textRun = constructTextRun(style, font, string, textRenderer().textLength() - m_start, respectHyphen ? &charactersWithHyphen : 0); if (respectHyphen) ePos = textRun.length(); - LayoutUnit selectionBottom = root()->selectionBottom(); - LayoutUnit selectionTop = root()->selectionTopAdjustedForPrecedingBlock(); + LayoutUnit selectionBottom = root().selectionBottom(); + LayoutUnit selectionTop = root().selectionTopAdjustedForPrecedingBlock(); - int deltaY = roundToInt(renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom - logicalBottom() : logicalTop() - selectionTop); + int deltaY = roundToInt(renderer().style()->isFlippedLinesWritingMode() ? selectionBottom - logicalBottom() : logicalTop() - selectionTop); int selHeight = max(0, roundToInt(selectionBottom - selectionTop)); FloatPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY); @@ -863,25 +862,34 @@ void InlineTextBox::paintSelection(GraphicsContext* context, const FloatPoint& b context->drawHighlightForText(font, textRun, localOrigin, selHeight, c, sPos, ePos); } -void InlineTextBox::paintCompositionBackground(GraphicsContext* context, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font, int startPos, int endPos) +unsigned InlineTextBox::underlinePaintStart(const CompositionUnderline& underline) +{ + return std::max(static_cast<unsigned>(m_start), underline.startOffset); +} + +unsigned InlineTextBox::underlinePaintEnd(const CompositionUnderline& underline) { - int offset = m_start; - int sPos = max(startPos - offset, 0); - int ePos = min(endPos - offset, (int)m_len); + unsigned paintEnd = std::min(end() + 1, underline.endOffset); // end() points at the last char, not past it. + if (m_truncation != cNoTruncation) + paintEnd = std::min(paintEnd, static_cast<unsigned>(m_start + m_truncation)); + return paintEnd; +} +void InlineTextBox::paintSingleCompositionBackgroundRun(GraphicsContext* context, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font, Color backgroundColor, int startPos, int endPos) +{ + int sPos = std::max(startPos - m_start, 0); + int ePos = std::min(endPos - m_start, static_cast<int>(m_len)); if (sPos >= ePos) return; GraphicsContextStateSaver stateSaver(*context); - Color c = Color(225, 221, 85); + updateGraphicsContext(context, backgroundColor, backgroundColor, 0); // Don't draw text at all! - updateGraphicsContext(context, c, c, 0); // Don't draw text at all! - - int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop(); + int deltaY = renderer().style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop(); int selHeight = selectionHeight(); FloatPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY); - context->drawHighlightForText(font, constructTextRun(style, font), localOrigin, selHeight, c, sPos, ePos); + context->drawHighlightForText(font, constructTextRun(style, font), localOrigin, selHeight, backgroundColor, sPos, ePos); } static StrokeStyle textDecorationStyleToStrokeStyle(TextDecorationStyle decorationStyle) @@ -912,7 +920,18 @@ static int computeUnderlineOffset(const TextUnderlinePosition underlinePosition, { // Compute the gap between the font and the underline. Use at least one // pixel gap, if underline is thick then use a bigger gap. - const int gap = std::max<int>(1, ceilf(textDecorationThickness / 2.f)); + int gap = 0; + + // Underline position of zero means draw underline on Baseline Position, + // in Blink we need at least 1-pixel gap to adding following check. + // Positive underline Position means underline should be drawn above baselin e + // and negative value means drawing below baseline, negating the value as in Blink + // downward Y-increases. + + if (fontMetrics.underlinePosition()) + gap = -fontMetrics.underlinePosition(); + else + gap = std::max<int>(1, ceilf(textDecorationThickness / 2.f)); // FIXME: We support only horizontal text for now. switch (underlinePosition) { @@ -920,7 +939,7 @@ static int computeUnderlineOffset(const TextUnderlinePosition underlinePosition, return fontMetrics.ascent() + gap; // Position underline near the alphabetic baseline. case TextUnderlinePositionUnder: { // Position underline relative to the under edge of the lowest element's content box. - const float offset = inlineTextBox->root()->maxLogicalTop() - inlineTextBox->logicalTop(); + const float offset = inlineTextBox->root().maxLogicalTop() - inlineTextBox->logicalTop(); if (offset > 0) return inlineTextBox->logicalHeight() + gap + offset; return inlineTextBox->logicalHeight() + gap; @@ -976,7 +995,7 @@ static void adjustStepToDecorationLength(float& step, float& controlPointDistanc * |-----------| * step */ -static void strokeWavyTextDecoration(GraphicsContext* context, FloatPoint& p1, FloatPoint& p2, float strokeThickness) +static void strokeWavyTextDecoration(GraphicsContext* context, FloatPoint p1, FloatPoint p2, float strokeThickness) { context->adjustLineToPixelBoundaries(p1, p2, strokeThickness, context->strokeStyle()); @@ -1053,7 +1072,39 @@ static void strokeWavyTextDecoration(GraphicsContext* context, FloatPoint& p1, F context->strokePath(path); } -void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& boxOrigin, TextDecoration deco, TextDecorationStyle decorationStyle, const ShadowList* shadowList) +static bool shouldSetDecorationAntialias(TextDecorationStyle decorationStyle) +{ + return decorationStyle == TextDecorationStyleDotted || decorationStyle == TextDecorationStyleDashed; +} + +static bool shouldSetDecorationAntialias(TextDecorationStyle underline, TextDecorationStyle overline, TextDecorationStyle linethrough) +{ + return shouldSetDecorationAntialias(underline) || shouldSetDecorationAntialias(overline) || shouldSetDecorationAntialias(linethrough); +} + +static void paintAppliedDecoration(GraphicsContext* context, FloatPoint start, float width, float doubleOffset, int wavyOffsetFactor, + RenderObject::AppliedTextDecoration decoration, float thickness, bool antialiasDecoration, bool isPrinting) +{ + context->setStrokeStyle(textDecorationStyleToStrokeStyle(decoration.style)); + context->setStrokeColor(decoration.color); + + switch (decoration.style) { + case TextDecorationStyleWavy: + strokeWavyTextDecoration(context, start + FloatPoint(0, doubleOffset * wavyOffsetFactor), start + FloatPoint(width, doubleOffset * wavyOffsetFactor), thickness); + break; + case TextDecorationStyleDotted: + case TextDecorationStyleDashed: + context->setShouldAntialias(antialiasDecoration); + // Fall through + default: + context->drawLineForText(start, width, isPrinting); + + if (decoration.style == TextDecorationStyleDouble) + context->drawLineForText(start + FloatPoint(0, doubleOffset), width, isPrinting); + } +} + +void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& boxOrigin, TextDecoration deco, const ShadowList* shadowList) { GraphicsContextStateSaver stateSaver(*context); @@ -1064,43 +1115,53 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& float width = m_logicalWidth; if (m_truncation != cNoTruncation) { - width = toRenderText(renderer())->width(m_start, m_truncation, textPos(), isFirstLineStyle()); + width = toRenderText(renderer()).width(m_start, m_truncation, textPos(), isLeftToRightDirection() ? LTR : RTL, isFirstLineStyle()); if (!isLeftToRightDirection()) localOrigin.move(m_logicalWidth - width, 0); } // Get the text decoration colors. - Color underline, overline, linethrough; - renderer()->getTextDecorationColors(deco, underline, overline, linethrough, true); + RenderObject::AppliedTextDecoration underline, overline, linethrough; + + renderer().getTextDecorations(deco, underline, overline, linethrough, true); if (isFirstLineStyle()) - renderer()->getTextDecorationColors(deco, underline, overline, linethrough, true, true); + renderer().getTextDecorations(deco, underline, overline, linethrough, true, true); // Use a special function for underlines to get the positioning exactly right. - bool isPrinting = textRenderer()->document().printing(); + bool isPrinting = textRenderer().document().printing(); - bool linesAreOpaque = !isPrinting && (!(deco & TextDecorationUnderline) || underline.alpha() == 255) && (!(deco & TextDecorationOverline) || overline.alpha() == 255) && (!(deco & TextDecorationLineThrough) || linethrough.alpha() == 255); + bool linesAreOpaque = !isPrinting && (!(deco & TextDecorationUnderline) || underline.color.alpha() == 255) && (!(deco & TextDecorationOverline) || overline.color.alpha() == 255) && (!(deco & TextDecorationLineThrough) || linethrough.color.alpha() == 255); - RenderStyle* styleToUse = renderer()->style(isFirstLineStyle()); + RenderStyle* styleToUse = renderer().style(isFirstLineStyle()); int baseline = styleToUse->fontMetrics().ascent(); size_t shadowCount = shadowList ? shadowList->shadows().size() : 0; // Set the thick of the line to be 10% (or something else ?)of the computed font size and not less than 1px. // Using computedFontSize should take care of zoom as well. - const float textDecorationThickness = std::max(1.f, styleToUse->computedFontSize() / 10.f); + + // Update Underline thickness, in case we have Faulty Font Metrics calculating underline thickness by old method. + float textDecorationThickness = styleToUse->fontMetrics().underlineThickness(); + int fontHeightInt = (int)(styleToUse->fontMetrics().floatHeight() + 0.5); + if ((textDecorationThickness == 0.f) || (textDecorationThickness >= (fontHeightInt >> 1))) + textDecorationThickness = std::max(1.f, styleToUse->computedFontSize() / 10.f); + context->setStrokeThickness(textDecorationThickness); - int extraOffset = 0; + bool antialiasDecoration = shouldSetDecorationAntialias(overline.style, underline.style, linethrough.style) + && RenderBoxModelObject::shouldAntialiasLines(context); + + float extraOffset = 0; if (!linesAreOpaque && shadowCount > 1) { FloatRect clipRect(localOrigin, FloatSize(width, baseline + 2)); for (size_t i = shadowCount; i--; ) { const ShadowData& s = shadowList->shadows()[i]; FloatRect shadowRect(localOrigin, FloatSize(width, baseline + 2)); shadowRect.inflate(s.blur()); - int shadowX = isHorizontal() ? s.x() : s.y(); - int shadowY = isHorizontal() ? s.y() : -s.x(); + float shadowX = isHorizontal() ? s.x() : s.y(); + float shadowY = isHorizontal() ? s.y() : -s.x(); shadowRect.move(shadowX, shadowY); clipRect.unite(shadowRect); - extraOffset = max(extraOffset, max(0, shadowY) + s.blur()); + extraOffset = max(extraOffset, max(0.0f, shadowY) + s.blur()); } context->clip(clipRect); extraOffset += baseline + 2; @@ -1116,60 +1177,24 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& extraOffset = 0; } const ShadowData& shadow = shadowList->shadows()[i]; - int shadowX = isHorizontal() ? shadow.x() : shadow.y(); - int shadowY = isHorizontal() ? shadow.y() : -shadow.x(); + float shadowX = isHorizontal() ? shadow.x() : shadow.y(); + float shadowY = isHorizontal() ? shadow.y() : -shadow.x(); context->setShadow(FloatSize(shadowX, shadowY - extraOffset), shadow.blur(), shadow.color()); } // Offset between lines - always non-zero, so lines never cross each other. float doubleOffset = textDecorationThickness + 1.f; - context->setStrokeStyle(textDecorationStyleToStrokeStyle(decorationStyle)); + if (deco & TextDecorationUnderline) { - context->setStrokeColor(underline); const int underlineOffset = computeUnderlineOffset(styleToUse->textUnderlinePosition(), styleToUse->fontMetrics(), this, textDecorationThickness); - switch (decorationStyle) { - case TextDecorationStyleWavy: { - FloatPoint start(localOrigin.x(), localOrigin.y() + underlineOffset + doubleOffset); - FloatPoint end(localOrigin.x() + width, localOrigin.y() + underlineOffset + doubleOffset); - strokeWavyTextDecoration(context, start, end, textDecorationThickness); - break; - } - default: - context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + underlineOffset), width, isPrinting); - - if (decorationStyle == TextDecorationStyleDouble) - context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + underlineOffset + doubleOffset), width, isPrinting); - } + paintAppliedDecoration(context, localOrigin + FloatPoint(0, underlineOffset), width, doubleOffset, 1, underline, textDecorationThickness, antialiasDecoration, isPrinting); } if (deco & TextDecorationOverline) { - context->setStrokeColor(overline); - switch (decorationStyle) { - case TextDecorationStyleWavy: { - FloatPoint start(localOrigin.x(), localOrigin.y() - doubleOffset); - FloatPoint end(localOrigin.x() + width, localOrigin.y() - doubleOffset); - strokeWavyTextDecoration(context, start, end, textDecorationThickness); - break; - } - default: - context->drawLineForText(localOrigin, width, isPrinting); - if (decorationStyle == TextDecorationStyleDouble) - context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() - doubleOffset), width, isPrinting); - } + paintAppliedDecoration(context, localOrigin, width, -doubleOffset, 1, overline, textDecorationThickness, antialiasDecoration, isPrinting); } if (deco & TextDecorationLineThrough) { - context->setStrokeColor(linethrough); - switch (decorationStyle) { - case TextDecorationStyleWavy: { - FloatPoint start(localOrigin.x(), localOrigin.y() + 2 * baseline / 3); - FloatPoint end(localOrigin.x() + width, localOrigin.y() + 2 * baseline / 3); - strokeWavyTextDecoration(context, start, end, textDecorationThickness); - break; - } - default: - context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + 2 * baseline / 3), width, isPrinting); - if (decorationStyle == TextDecorationStyleDouble) - context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + doubleOffset + 2 * baseline / 3), width, isPrinting); - } + const float lineThroughOffset = 2 * baseline / 3; + paintAppliedDecoration(context, localOrigin + FloatPoint(0, lineThroughOffset), width, doubleOffset, 0, linethrough, textDecorationThickness, antialiasDecoration, isPrinting); } } } @@ -1190,7 +1215,7 @@ static GraphicsContext::DocumentMarkerLineStyle lineStyleForMarkerType(DocumentM 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()) + if (textRenderer().document().printing()) return; if (m_truncation == cFullTruncation) @@ -1216,7 +1241,7 @@ void InlineTextBox::paintDocumentMarker(GraphicsContext* pt, const FloatPoint& b endPosition = min<int>(endPosition, m_truncation); // Calculate start & width - int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop(); + int deltaY = renderer().style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop(); int selHeight = selectionHeight(); FloatPoint startPoint(boxOrigin.x(), boxOrigin.y() - deltaY); TextRun run = constructTextRun(style, font); @@ -1230,7 +1255,7 @@ void InlineTextBox::paintDocumentMarker(GraphicsContext* pt, const FloatPoint& b // display a toolTip. We don't do this for misspelling markers. if (grammar) { markerRect.move(-boxOrigin.x(), -boxOrigin.y()); - markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox(); + markerRect = renderer().localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox(); toRenderedDocumentMarker(marker)->setRenderedRect(markerRect); } } @@ -1242,7 +1267,7 @@ void InlineTextBox::paintDocumentMarker(GraphicsContext* pt, const FloatPoint& b // 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 = misspellingLineThickness; - int baseline = renderer()->style(isFirstLineStyle())->fontMetrics().ascent(); + int baseline = renderer().style(isFirstLineStyle())->fontMetrics().ascent(); int descent = logicalHeight() - baseline; int underlineOffset; if (descent <= (2 + lineThickness)) { @@ -1259,7 +1284,7 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, const FloatPoint& { // Use same y positioning and height as for selection, so that when the selection and this highlight are on // the same word there are no pieces sticking out. - int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop(); + int deltaY = renderer().style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop(); int selHeight = selectionHeight(); int sPos = max(marker->startOffset() - m_start, (unsigned)0); @@ -1268,11 +1293,11 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, const FloatPoint& // Always compute and store the rect associated with this marker. The computed rect is in absolute coordinates. IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, IntPoint(x(), selectionTop()), selHeight, sPos, ePos)); - markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox(); + markerRect = renderer().localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox(); toRenderedDocumentMarker(marker)->setRenderedRect(markerRect); // Optionally highlight the text - if (renderer()->frame()->editor().markedTextMatchesAreHighlighted()) { + if (renderer().frame()->editor().markedTextMatchesAreHighlighted()) { Color color = marker->activeMatch() ? RenderTheme::theme().platformActiveTextSearchHighlightColor() : RenderTheme::theme().platformInactiveTextSearchHighlightColor(); @@ -1283,17 +1308,36 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, const FloatPoint& } } +void InlineTextBox::paintCompositionBackgrounds(GraphicsContext* pt, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font, bool useCustomUnderlines) +{ + if (useCustomUnderlines) { + // Paint custom background highlights for compositions. + const Vector<CompositionUnderline>& underlines = renderer().frame()->inputMethodController().customCompositionUnderlines(); + CompositionUnderlineRangeFilter filter(underlines, start(), end()); + for (CompositionUnderlineRangeFilter::ConstIterator it = filter.begin(); it != filter.end(); ++it) { + if (it->backgroundColor == Color::transparent) + continue; + paintSingleCompositionBackgroundRun(pt, boxOrigin, style, font, it->backgroundColor, underlinePaintStart(*it), underlinePaintEnd(*it)); + } + + } else { + paintSingleCompositionBackgroundRun(pt, boxOrigin, style, font, RenderTheme::theme().platformDefaultCompositionBackgroundColor(), + renderer().frame()->inputMethodController().compositionStart(), + renderer().frame()->inputMethodController().compositionEnd()); + } +} + void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font, bool background) { - if (!renderer()->node()) + if (!renderer().node()) return; - Vector<DocumentMarker*> markers = renderer()->document().markers()->markersFor(renderer()->node()); - Vector<DocumentMarker*>::const_iterator markerIt = markers.begin(); + WillBeHeapVector<DocumentMarker*> markers = renderer().document().markers().markersFor(renderer().node()); + WillBeHeapVector<DocumentMarker*>::const_iterator markerIt = markers.begin(); // Give any document markers that touch this run a chance to draw before the text has been drawn. // Note end() points at the last char, not one past it like endOffset and ranges do. - for ( ; markerIt != markers.end(); markerIt++) { + for ( ; markerIt != markers.end(); ++markerIt) { DocumentMarker* marker = *markerIt; // Paint either the background markers or the foreground markers, but not both @@ -1343,33 +1387,21 @@ void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, const FloatP if (m_truncation == cFullTruncation) return; - float start = 0; // start of line to draw, relative to tx - float width = m_logicalWidth; // how much line to draw - bool useWholeWidth = true; - unsigned paintStart = m_start; - unsigned paintEnd = end() + 1; // end points at the last char, not past it - if (paintStart <= underline.startOffset) { - paintStart = underline.startOffset; - useWholeWidth = false; - 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); - useWholeWidth = false; - } - if (m_truncation != cNoTruncation) { - paintEnd = min(paintEnd, (unsigned)m_start + m_truncation); - useWholeWidth = false; - } - if (!useWholeWidth) { - width = toRenderText(renderer())->width(paintStart, paintEnd - paintStart, textPos() + start, isFirstLineStyle()); - } + unsigned paintStart = underlinePaintStart(underline); + unsigned paintEnd = underlinePaintEnd(underline); + + // start of line to draw, relative to paintOffset. + float start = paintStart == static_cast<unsigned>(m_start) ? 0 : + toRenderText(renderer()).width(m_start, paintStart - m_start, textPos(), isLeftToRightDirection() ? LTR : RTL, isFirstLineStyle()); + // how much line to draw + float width = (paintStart == static_cast<unsigned>(m_start) && paintEnd == static_cast<unsigned>(end()) + 1) ? m_logicalWidth : + toRenderText(renderer()).width(paintStart, paintEnd - paintStart, textPos() + start, isLeftToRightDirection() ? LTR : RTL, 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(isFirstLineStyle())->fontMetrics().ascent(); + int baseline = renderer().style(isFirstLineStyle())->fontMetrics().ascent(); if (underline.thick && logicalHeight() - baseline >= 2) lineThickness = 2; @@ -1380,7 +1412,7 @@ void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, const FloatP ctx->setStrokeColor(underline.color); ctx->setStrokeThickness(lineThickness); - ctx->drawLineForText(FloatPoint(boxOrigin.x() + start, boxOrigin.y() + logicalHeight() - lineThickness), width, textRenderer()->document().printing()); + ctx->drawLineForText(FloatPoint(boxOrigin.x() + start, boxOrigin.y() + logicalHeight() - lineThickness), width, textRenderer().document().printing()); } int InlineTextBox::caretMinOffset() const @@ -1399,7 +1431,7 @@ float InlineTextBox::textPos() const // from the containing block edge in its measurement. textPos() should be consistent so the text are rendered in the same width. if (logicalLeft() == 0) return 0; - return logicalLeft() - root()->logicalLeft(); + return logicalLeft() - root().logicalLeft(); } int InlineTextBox::offsetForPosition(float lineOffset, bool includePartialGlyphs) const @@ -1414,8 +1446,8 @@ int InlineTextBox::offsetForPosition(float lineOffset, bool includePartialGlyphs FontCachePurgePreventer fontCachePurgePreventer; - RenderText* text = toRenderText(renderer()); - RenderStyle* style = text->style(isFirstLineStyle()); + RenderText& text = toRenderText(renderer()); + RenderStyle* style = text.style(isFirstLineStyle()); const Font& font = style->font(); return font.offsetForPosition(constructTextRun(style, font), lineOffset - logicalLeft(), includePartialGlyphs); } @@ -1430,8 +1462,8 @@ float InlineTextBox::positionForOffset(int offset) const FontCachePurgePreventer fontCachePurgePreventer; - RenderText* text = toRenderText(renderer()); - RenderStyle* styleToUse = text->style(isFirstLineStyle()); + RenderText& text = toRenderText(renderer()); + RenderStyle* styleToUse = text.style(isFirstLineStyle()); ASSERT(styleToUse); const Font& font = styleToUse->font(); int from = !isLeftToRightDirection() ? offset - m_start : 0; @@ -1468,8 +1500,7 @@ void InlineTextBox::characterWidths(Vector<float>& widths) const { FontCachePurgePreventer fontCachePurgePreventer; - RenderText* textObj = textRenderer(); - RenderStyle* styleToUse = textObj->style(isFirstLineStyle()); + RenderStyle* styleToUse = textRenderer().style(isFirstLineStyle()); const Font& font = styleToUse->font(); TextRun textRun = constructTextRun(styleToUse, font); @@ -1488,28 +1519,22 @@ void InlineTextBox::characterWidths(Vector<float>& widths) const TextRun InlineTextBox::constructTextRun(RenderStyle* style, const Font& font, StringBuilder* charactersWithHyphen) const { ASSERT(style); + ASSERT(textRenderer().text()); - RenderText* textRenderer = this->textRenderer(); - ASSERT(textRenderer); - ASSERT(textRenderer->text()); - - StringView string = textRenderer->text().createView(); + StringView string = textRenderer().text().createView(); unsigned startPos = start(); unsigned length = len(); if (string.length() != length || startPos) string.narrow(startPos, length); - return constructTextRun(style, font, string, textRenderer->textLength() - startPos, charactersWithHyphen); + return constructTextRun(style, font, string, textRenderer().textLength() - startPos, charactersWithHyphen); } TextRun InlineTextBox::constructTextRun(RenderStyle* style, const Font& font, StringView string, int maximumLength, StringBuilder* charactersWithHyphen) const { ASSERT(style); - RenderText* textRenderer = this->textRenderer(); - ASSERT(textRenderer); - if (charactersWithHyphen) { const AtomicString& hyphenString = style->hyphenString(); charactersWithHyphen->reserveCapacity(string.length() + hyphenString.length()); @@ -1521,10 +1546,11 @@ TextRun InlineTextBox::constructTextRun(RenderStyle* style, const Font& font, St ASSERT(maximumLength >= static_cast<int>(string.length())); - TextRun run(string, textPos(), expansion(), expansionBehavior(), direction(), dirOverride() || style->rtlOrdering() == VisualOrder, !textRenderer->canUseSimpleFontCodePath()); + TextRun run(string, textPos(), expansion(), expansionBehavior(), direction(), dirOverride() || style->rtlOrdering() == VisualOrder, !textRenderer().canUseSimpleFontCodePath()); run.setTabSize(!style->collapseWhiteSpace(), style->tabSize()); + run.setCharacterScanForCodePath(!textRenderer().canUseSimpleFontCodePath()); if (textRunNeedsRenderingContext(font)) - run.setRenderingContext(SVGTextRunRenderingContext::create(textRenderer)); + run.setRenderingContext(SVGTextRunRenderingContext::create(&textRenderer())); // Propagate the maximum length of the characters buffer to the TextRun, even when we're only processing a substring. run.setCharactersLength(maximumLength); @@ -1546,15 +1572,15 @@ const char* InlineTextBox::boxName() const void InlineTextBox::showBox(int printedCharacters) const { - const RenderText* obj = toRenderText(renderer()); - String value = obj->text(); + const RenderText& obj = toRenderText(renderer()); + String value = obj.text(); value = value.substring(start(), len()); value.replaceWithLiteral('\\', "\\\\"); value.replaceWithLiteral('\n', "\\n"); printedCharacters += fprintf(stderr, "%s\t%p", boxName(), this); for (; printedCharacters < showTreeCharacterOffset; printedCharacters++) fputc(' ', stderr); - printedCharacters = fprintf(stderr, "\t%s %p", obj->renderName(), obj); + printedCharacters = fprintf(stderr, "\t%s %p", obj.renderName(), &obj); const int rendererCharacterOffset = 24; for (; printedCharacters < rendererCharacterOffset; printedCharacters++) fputc(' ', stderr); diff --git a/chromium/third_party/WebKit/Source/core/rendering/InlineTextBox.h b/chromium/third_party/WebKit/Source/core/rendering/InlineTextBox.h index 27579edf5cb..5c0a6f0f338 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/InlineTextBox.h +++ b/chromium/third_party/WebKit/Source/core/rendering/InlineTextBox.h @@ -25,7 +25,6 @@ #include "core/rendering/InlineBox.h" #include "core/rendering/RenderText.h" // so textRenderer() can be inline -#include "platform/graphics/GraphicsContext.h" #include "platform/text/TextRun.h" #include "wtf/Forward.h" @@ -33,6 +32,7 @@ namespace WebCore { struct CompositionUnderline; class DocumentMarker; +class GraphicsContext; const unsigned short cNoTruncation = USHRT_MAX; const unsigned short cFullTruncation = USHRT_MAX - 1; @@ -43,7 +43,7 @@ Color correctedTextColor(Color textColor, Color backgroundColor); class InlineTextBox : public InlineBox { public: - InlineTextBox(RenderObject* obj) + InlineTextBox(RenderObject& obj) : InlineBox(obj) , m_prevTextBox(0) , m_nextTextBox(0) @@ -72,7 +72,7 @@ public: unsigned short truncation() { return m_truncation; } - virtual void markDirty(bool dirty = true) OVERRIDE FINAL; + virtual void markDirty() OVERRIDE FINAL; using InlineBox::hasHyphen; using InlineBox::setHasHyphen; @@ -94,8 +94,8 @@ public: LayoutUnit logicalRightVisualOverflow() const { return logicalOverflowRect().maxX(); } #ifndef NDEBUG - virtual void showBox(int = 0) const; - virtual const char* boxName() const; + virtual void showBox(int = 0) const OVERRIDE; + virtual const char* boxName() const OVERRIDE; #endif enum RotationDirection { Counterclockwise, Clockwise }; @@ -111,18 +111,18 @@ private: public: TextRun constructTextRunForInspector(RenderStyle*, const Font&) const; - virtual FloatRect calculateBoundaries() const { return FloatRect(x(), y(), width(), height()); } + virtual FloatRect calculateBoundaries() const OVERRIDE { return FloatRect(x(), y(), width(), height()); } virtual LayoutRect localSelectionRect(int startPos, int endPos); bool isSelected(int startPos, int endPos) const; void selectionStartEnd(int& sPos, int& ePos); protected: - virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); + virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; public: - RenderText* textRenderer() const; + RenderText& textRenderer() const; private: virtual void deleteLine() OVERRIDE FINAL; @@ -175,16 +175,22 @@ private: unsigned short m_truncation; // Where to truncate when text overflow is applied. We use special constants to // denote no truncation (the whole run paints) and full truncation (nothing paints at all). + unsigned underlinePaintStart(const CompositionUnderline&); + unsigned underlinePaintEnd(const CompositionUnderline&); + protected: - void paintCompositionBackground(GraphicsContext*, const FloatPoint& boxOrigin, RenderStyle*, const Font&, int startPos, int endPos); + void paintSingleCompositionBackgroundRun(GraphicsContext*, const FloatPoint& boxOrigin, RenderStyle*, const Font&, Color backgroundColor, int startPos, int endPos); + void paintCompositionBackgrounds(GraphicsContext*, const FloatPoint& boxOrigin, RenderStyle*, const Font&, bool useCustomUnderlines); void paintDocumentMarkers(GraphicsContext*, const FloatPoint& boxOrigin, RenderStyle*, const Font&, bool background); void paintCompositionUnderline(GraphicsContext*, const FloatPoint& boxOrigin, const CompositionUnderline&); + // These functions both paint markers and update the DocumentMarker's renderedRect. + virtual void paintDocumentMarker(GraphicsContext*, const FloatPoint& boxOrigin, DocumentMarker*, RenderStyle*, const Font&, bool grammar); + virtual void paintTextMatchMarker(GraphicsContext*, const FloatPoint& boxOrigin, DocumentMarker*, RenderStyle*, const Font&); + private: - void paintDecoration(GraphicsContext*, const FloatPoint& boxOrigin, TextDecoration, TextDecorationStyle, const ShadowList*); + void paintDecoration(GraphicsContext*, const FloatPoint& boxOrigin, TextDecoration, const ShadowList*); void paintSelection(GraphicsContext*, const FloatPoint& boxOrigin, RenderStyle*, const Font&, Color textColor); - void paintDocumentMarker(GraphicsContext*, const FloatPoint& boxOrigin, DocumentMarker*, RenderStyle*, const Font&, bool grammar); - void paintTextMatchMarker(GraphicsContext*, const FloatPoint& boxOrigin, DocumentMarker*, RenderStyle*, const Font&); TextRun::ExpansionBehavior expansionBehavior() const { @@ -195,7 +201,7 @@ private: DEFINE_INLINE_BOX_TYPE_CASTS(InlineTextBox); -inline RenderText* InlineTextBox::textRenderer() const +inline RenderText& InlineTextBox::textRenderer() const { return toRenderText(renderer()); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/LayerPaintingInfo.h b/chromium/third_party/WebKit/Source/core/rendering/LayerPaintingInfo.h index b9af0314271..421e61b2f09 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/LayerPaintingInfo.h +++ b/chromium/third_party/WebKit/Source/core/rendering/LayerPaintingInfo.h @@ -74,13 +74,12 @@ typedef unsigned PaintLayerFlags; struct LayerPaintingInfo { LayerPaintingInfo(RenderLayer* inRootLayer, const LayoutRect& inDirtyRect, PaintBehavior inPaintBehavior, const LayoutSize& inSubPixelAccumulation, - RenderObject* inPaintingRoot = 0, RenderRegion*inRegion = 0, + RenderObject* inPaintingRoot = 0, OverlapTestRequestMap* inOverlapTestRequests = 0) : rootLayer(inRootLayer) , paintingRoot(inPaintingRoot) , paintDirtyRect(inDirtyRect) , subPixelAccumulation(inSubPixelAccumulation) - , region(inRegion) , overlapTestRequests(inOverlapTestRequests) , paintBehavior(inPaintBehavior) , clipToDirtyRect(true) @@ -89,7 +88,6 @@ struct LayerPaintingInfo { RenderObject* paintingRoot; // only paint descendants of this object LayoutRect paintDirtyRect; // relative to rootLayer; LayoutSize subPixelAccumulation; - RenderRegion* region; // May be null. OverlapTestRequestMap* overlapTestRequests; // May be null. PaintBehavior paintBehavior; bool clipToDirtyRect; diff --git a/chromium/third_party/WebKit/Source/core/rendering/LayoutIndicator.cpp b/chromium/third_party/WebKit/Source/core/rendering/LayoutIndicator.cpp deleted file mode 100644 index a57c53c11d1..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/LayoutIndicator.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2013 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: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT - * OWNER 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 "core/rendering/LayoutIndicator.h" - -namespace WebCore { - -#ifndef NDEBUG - -size_t LayoutIndicator::s_inLayout = 0; - -#endif - -} diff --git a/chromium/third_party/WebKit/Source/core/rendering/LayoutIndicator.h b/chromium/third_party/WebKit/Source/core/rendering/LayoutIndicator.h deleted file mode 100644 index 6337da949cf..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/LayoutIndicator.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2013 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: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT - * OWNER 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 LayoutIndicator_h -#define LayoutIndicator_h - -#include "wtf/Assertions.h" - -namespace WebCore { - -#ifndef NDEBUG - -class LayoutIndicator { -public: - LayoutIndicator() { ++s_inLayout; } - ~LayoutIndicator() { --s_inLayout; } - - static bool inLayout() { return s_inLayout; } - -private: - static size_t s_inLayout; -}; - -#else - -class LayoutIndicator { -public: - LayoutIndicator() { } - ~LayoutIndicator() { } -}; - -#endif - -} - -#endif // LayoutIndicator_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/LayoutRectRecorder.cpp b/chromium/third_party/WebKit/Source/core/rendering/LayoutRectRecorder.cpp deleted file mode 100644 index 90c50d32884..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/LayoutRectRecorder.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2013, 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: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT - * OWNER 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 "core/rendering/LayoutRectRecorder.h" - -#include "core/rendering/RenderObject.h" - -namespace WebCore { - -bool LayoutRectRecorder::shouldRecordLayoutRects() -{ - bool isTracing; - TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("blink.debug.layout"), &isTracing); - return RuntimeEnabledFeatures::repaintAfterLayoutEnabled() || isTracing; -} - -LayoutRectRecorder::LayoutRectRecorder(RenderObject& object, bool skipRecording) - : m_object(object) - , m_skipRecording(skipRecording) -{ - if (!shouldRecordLayoutRects()) - return; - if (m_skipRecording) - return; - - if (!m_object.layoutDidGetCalled()) - m_object.setOldRepaintRect(m_object.clippedOverflowRectForRepaint(m_object.containerForRepaint())); - - // If should do repaint was set previously make sure we don't accidentally unset it. - if (!m_object.shouldDoFullRepaintAfterLayout()) - m_object.setShouldDoFullRepaintAfterLayout(m_object.selfNeedsLayout()); - - m_object.setLayoutDidGetCalled(true); -} - -LayoutRectRecorder::~LayoutRectRecorder() -{ - if (!shouldRecordLayoutRects()) - return; - if (m_skipRecording) - return; - - // Note, we don't store the repaint container because it can change during layout. - m_object.setNewRepaintRect(m_object.clippedOverflowRectForRepaint(m_object.containerForRepaint())); -} - -} // namespace WebCore - diff --git a/chromium/third_party/WebKit/Source/core/rendering/LayoutRectRecorder.h b/chromium/third_party/WebKit/Source/core/rendering/LayoutRectRecorder.h deleted file mode 100644 index c92eb5efc90..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/LayoutRectRecorder.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2013, 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: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT - * OWNER 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 LayoutRectRecorder_h -#define LayoutRectRecorder_h - -#include "platform/geometry/LayoutRect.h" -#include "wtf/Noncopyable.h" - -namespace WebCore { - -class RenderLayerModelObject; -class RenderObject; - -class LayoutRectRecorder { - WTF_MAKE_NONCOPYABLE(LayoutRectRecorder); -public: - LayoutRectRecorder(RenderObject&, bool skipRecording = false); - ~LayoutRectRecorder(); - - static bool shouldRecordLayoutRects(); - -private: - RenderObject& m_object; - bool m_skipRecording; -}; - -} // namespace WebCore - -#endif // LayoutRectRecorder_h - diff --git a/chromium/third_party/WebKit/Source/core/rendering/LayoutRepainter.cpp b/chromium/third_party/WebKit/Source/core/rendering/LayoutRepainter.cpp index fc06e0b3b21..046222e8729 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/LayoutRepainter.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/LayoutRepainter.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "core/rendering/LayoutRepainter.h" +#include "core/rendering/RenderLayer.h" #include "core/rendering/RenderObject.h" namespace WebCore { @@ -39,9 +40,13 @@ LayoutRepainter::LayoutRepainter(RenderObject& object, bool checkForRepaint) return; if (m_checkForRepaint) { - m_repaintContainer = m_object.containerForRepaint(); - m_oldBounds = m_object.clippedOverflowRectForRepaint(m_repaintContainer); - m_oldOutlineBox = m_object.outlineBoundsForRepaint(m_repaintContainer); + m_repaintContainer = m_object.containerForPaintInvalidation(); + { + // Hits in compositing/video/video-controls-layer-creation.html + DisableCompositingQueryAsserts disabler; + m_oldBounds = m_object.boundsRectForPaintInvalidation(m_repaintContainer); + m_oldOffset = RenderLayer::positionFromPaintInvalidationContainer(&m_object, m_repaintContainer); + } } } @@ -50,7 +55,10 @@ bool LayoutRepainter::repaintAfterLayout() if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) return false; - return m_checkForRepaint ? m_object.repaintAfterLayoutIfNeeded(m_repaintContainer, m_object.selfNeedsLayout(), m_oldBounds, m_oldOutlineBox) : false; + // Hits in compositing/video/video-controls-layer-creation.html + DisableCompositingQueryAsserts disabler; + + return m_checkForRepaint ? m_object.invalidatePaintAfterLayoutIfNeeded(m_repaintContainer, m_object.selfNeedsLayout(), m_oldBounds, m_oldOffset) : false; } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/LayoutRepainter.h b/chromium/third_party/WebKit/Source/core/rendering/LayoutRepainter.h index 55fdd1eb23a..30a3aef00c5 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/LayoutRepainter.h +++ b/chromium/third_party/WebKit/Source/core/rendering/LayoutRepainter.h @@ -44,10 +44,10 @@ public: private: RenderObject& m_object; - RenderLayerModelObject* m_repaintContainer; + const RenderLayerModelObject* m_repaintContainer; // We store these values as LayoutRects, but the final invalidations will be pixel snapped LayoutRect m_oldBounds; - LayoutRect m_oldOutlineBox; + LayoutPoint m_oldOffset; bool m_checkForRepaint; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/LayoutState.cpp b/chromium/third_party/WebKit/Source/core/rendering/LayoutState.cpp index 940f21ccc16..45c0d76f1ac 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/LayoutState.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/LayoutState.cpp @@ -33,27 +33,42 @@ namespace WebCore { -LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const LayoutSize& offset, LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged, ColumnInfo* columnInfo) - : m_columnInfo(columnInfo) - , m_lineGrid(0) - , m_next(prev) - , m_shapeInsideInfo(0) -#ifndef NDEBUG - , m_renderer(renderer) +LayoutState::LayoutState(LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged, RenderView& view) + : m_clipped(false) + , m_isPaginated(pageLogicalHeight) + , m_pageLogicalHeightChanged(pageLogicalHeightChanged) + , m_cachedOffsetsEnabled(true) +#if ASSERT_ENABLED + , m_layoutDeltaXSaturated(false) + , m_layoutDeltaYSaturated(false) #endif + , m_columnInfo(0) + , m_next(0) + , m_pageLogicalHeight(pageLogicalHeight) + , m_renderer(view) { - ASSERT(m_next); + ASSERT(!view.layoutState()); + view.pushLayoutState(*this); +} - bool fixed = renderer->isOutOfFlowPositioned() && renderer->style()->position() == FixedPosition; +LayoutState::LayoutState(RenderBox& renderer, const LayoutSize& offset, LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged, ColumnInfo* columnInfo) + : m_columnInfo(columnInfo) + , m_next(renderer.view()->layoutState()) + , m_renderer(renderer) +{ + renderer.view()->pushLayoutState(*this); + m_cachedOffsetsEnabled = m_next->m_cachedOffsetsEnabled && renderer.supportsLayoutStateCachedOffsets(); + bool fixed = renderer.isOutOfFlowPositioned() && renderer.style()->position() == FixedPosition; if (fixed) { // FIXME: This doesn't work correctly with transforms. - FloatPoint fixedOffset = renderer->view()->localToAbsolute(FloatPoint(), IsFixed); + FloatPoint fixedOffset = renderer.view()->localToAbsolute(FloatPoint(), IsFixed); m_paintOffset = LayoutSize(fixedOffset.x(), fixedOffset.y()) + offset; - } else - m_paintOffset = prev->m_paintOffset + offset; + } else { + m_paintOffset = m_next->m_paintOffset + offset; + } - if (renderer->isOutOfFlowPositioned() && !fixed) { - if (RenderObject* container = renderer->container()) { + if (renderer.isOutOfFlowPositioned() && !fixed) { + if (RenderObject* container = renderer.container()) { if (container->isInFlowPositioned() && container->isRenderInline()) m_paintOffset += toRenderInline(container)->offsetForInFlowPositionedInline(renderer); } @@ -61,15 +76,17 @@ LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const LayoutSiz m_layoutOffset = m_paintOffset; - if (renderer->isInFlowPositioned() && renderer->hasLayer()) - m_paintOffset += renderer->layer()->offsetForInFlowPosition(); + if (renderer.isInFlowPositioned() && renderer.hasLayer()) + m_paintOffset += renderer.layer()->offsetForInFlowPosition(); - m_clipped = !fixed && prev->m_clipped; + m_clipped = !fixed && m_next->m_clipped; if (m_clipped) - m_clipRect = prev->m_clipRect; + m_clipRect = m_next->m_clipRect; + + if (renderer.hasOverflowClip()) { + LayoutSize deltaSize = RuntimeEnabledFeatures::repaintAfterLayoutEnabled() ? LayoutSize() : renderer.view()->layoutDelta(); - if (renderer->hasOverflowClip()) { - LayoutRect clipRect(toPoint(m_paintOffset) + renderer->view()->layoutDelta(), renderer->cachedSizeForOverflowClip()); + LayoutRect clipRect(toPoint(m_paintOffset) + deltaSize, renderer.cachedSizeForOverflowClip()); if (m_clipped) m_clipRect.intersect(clipRect); else { @@ -77,17 +94,18 @@ LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const LayoutSiz m_clipped = true; } - m_paintOffset -= renderer->scrolledContentOffset(); + m_paintOffset -= renderer.scrolledContentOffset(); } // If we establish a new page height, then cache the offset to the top of the first page. // We can compare this later on to figure out what part of the page we're actually on, - if (pageLogicalHeight || m_columnInfo || renderer->isRenderFlowThread()) { + if (pageLogicalHeight || m_columnInfo || renderer.isRenderFlowThread()) { m_pageLogicalHeight = pageLogicalHeight; - bool isFlipped = renderer->style()->isFlippedBlocksWritingMode(); - m_pageOffset = LayoutSize(m_layoutOffset.width() + (!isFlipped ? renderer->borderLeft() + renderer->paddingLeft() : renderer->borderRight() + renderer->paddingRight()), - m_layoutOffset.height() + (!isFlipped ? renderer->borderTop() + renderer->paddingTop() : renderer->borderBottom() + renderer->paddingBottom())); + bool isFlipped = renderer.style()->isFlippedBlocksWritingMode(); + m_pageOffset = LayoutSize(m_layoutOffset.width() + (!isFlipped ? renderer.borderLeft() + renderer.paddingLeft() : renderer.borderRight() + renderer.paddingRight()), + m_layoutOffset.height() + (!isFlipped ? renderer.borderTop() + renderer.paddingTop() : renderer.borderBottom() + renderer.paddingBottom())); m_pageLogicalHeightChanged = pageLogicalHeightChanged; + m_isPaginated = true; } else { // If we don't establish a new page height, then propagate the old page height and offset down. m_pageLogicalHeight = m_next->m_pageLogicalHeight; @@ -96,59 +114,62 @@ LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const LayoutSiz // Disable pagination for objects we don't support. For now this includes overflow:scroll/auto, inline blocks and // writing mode roots. - if (renderer->isUnsplittableForPagination()) + if (renderer.isUnsplittableForPagination()) { m_pageLogicalHeight = 0; + m_isPaginated = false; + } else { + m_isPaginated = m_pageLogicalHeight || m_next->m_columnInfo || renderer.flowThreadContainingBlock(); + } } - // Propagate line grid information. - propagateLineGridInfo(renderer); - if (!m_columnInfo) m_columnInfo = m_next->m_columnInfo; - if (renderer->isRenderBlock()) { - const RenderBlock* renderBlock = toRenderBlock(renderer); - m_shapeInsideInfo = renderBlock->shapeInsideInfo(); - if (!m_shapeInsideInfo && m_next->m_shapeInsideInfo && renderBlock->allowsShapeInsideInfoSharing(m_next->m_shapeInsideInfo->owner())) - m_shapeInsideInfo = m_next->m_shapeInsideInfo; - } - - m_layoutDelta = m_next->m_layoutDelta; -#if !ASSERT_DISABLED - m_layoutDeltaXSaturated = m_next->m_layoutDeltaXSaturated; - m_layoutDeltaYSaturated = m_next->m_layoutDeltaYSaturated; + if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) { + m_layoutDelta = m_next->m_layoutDelta; +#if ASSERT_ENABLED + m_layoutDeltaXSaturated = m_next->m_layoutDeltaXSaturated; + m_layoutDeltaYSaturated = m_next->m_layoutDeltaYSaturated; #endif - - m_isPaginated = m_pageLogicalHeight || m_columnInfo || renderer->isRenderFlowThread(); - - if (lineGrid() && renderer->hasColumns() && renderer->style()->hasInlineColumnAxis()) - computeLineGridPaginationOrigin(renderer); - - // If we have a new grid to track, then add it to our set. - if (renderer->style()->lineGrid() != RenderStyle::initialLineGrid() && renderer->isRenderBlockFlow()) - establishLineGrid(toRenderBlockFlow(renderer)); + } // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present. } -LayoutState::LayoutState(RenderObject* root) +inline static bool shouldDisableLayoutStateForSubtree(RenderObject& renderer) +{ + RenderObject* object = &renderer; + while (object) { + if (object->supportsLayoutStateCachedOffsets()) + return true; + object = object->container(); + } + return false; +} + +LayoutState::LayoutState(RenderObject& root) : m_clipped(false) , m_isPaginated(false) , m_pageLogicalHeightChanged(false) -#if !ASSERT_DISABLED + , m_cachedOffsetsEnabled(shouldDisableLayoutStateForSubtree(root)) +#if ASSERT_ENABLED , m_layoutDeltaXSaturated(false) , m_layoutDeltaYSaturated(false) #endif , m_columnInfo(0) - , m_lineGrid(0) - , m_next(0) - , m_shapeInsideInfo(0) + , m_next(root.view()->layoutState()) , m_pageLogicalHeight(0) -#ifndef NDEBUG , m_renderer(root) -#endif { - RenderObject* container = root->container(); + // FIXME: Why does RenderTableSection create this wonky LayoutState? + ASSERT(!m_next || root.isTableSection()); + // We'll end up pushing in RenderView itself, so don't bother adding it. + if (root.isRenderView()) + return; + + root.view()->pushLayoutState(*this); + + RenderObject* container = root.container(); FloatPoint absContentPoint = container->localToAbsolute(FloatPoint(), UseTransforms); m_paintOffset = LayoutSize(absContentPoint.x(), absContentPoint.y()); @@ -160,14 +181,12 @@ LayoutState::LayoutState(RenderObject* root) } } -void* LayoutState::operator new(size_t sz) -{ - return partitionAlloc(Partitions::getRenderingPartition(), sz); -} - -void LayoutState::operator delete(void* ptr) +LayoutState::~LayoutState() { - partitionFree(ptr); + if (m_renderer.view()->layoutState()) { + ASSERT(m_renderer.view()->layoutState() == this); + m_renderer.view()->popLayoutState(); + } } void LayoutState::clearPaginationInformation() @@ -177,98 +196,18 @@ void LayoutState::clearPaginationInformation() m_columnInfo = m_next->m_columnInfo; } -LayoutUnit LayoutState::pageLogicalOffset(RenderBox* child, LayoutUnit childLogicalOffset) const +LayoutUnit LayoutState::pageLogicalOffset(const RenderBox& child, const LayoutUnit& childLogicalOffset) const { - if (child->isHorizontalWritingMode()) + if (child.isHorizontalWritingMode()) return m_layoutOffset.height() + childLogicalOffset - m_pageOffset.height(); return m_layoutOffset.width() + childLogicalOffset - m_pageOffset.width(); } -void LayoutState::addForcedColumnBreak(RenderBox* child, LayoutUnit childLogicalOffset) +void LayoutState::addForcedColumnBreak(const RenderBox& child, const LayoutUnit& childLogicalOffset) { if (!m_columnInfo || m_columnInfo->columnHeight()) return; m_columnInfo->addForcedBreak(pageLogicalOffset(child, childLogicalOffset)); } -void LayoutState::propagateLineGridInfo(RenderBox* renderer) -{ - // Disable line grids for objects we don't support. For now this includes overflow:scroll/auto, inline blocks and - // writing mode roots. - if (!m_next || renderer->isUnsplittableForPagination()) - return; - - m_lineGrid = m_next->m_lineGrid; - m_lineGridOffset = m_next->m_lineGridOffset; - m_lineGridPaginationOrigin = m_next->m_lineGridPaginationOrigin; -} - -void LayoutState::establishLineGrid(RenderBlockFlow* block) -{ - // First check to see if this grid has been established already. - if (m_lineGrid) { - if (m_lineGrid->style()->lineGrid() == block->style()->lineGrid()) - return; - RenderBlockFlow* currentGrid = m_lineGrid; - for (LayoutState* currentState = m_next; currentState; currentState = currentState->m_next) { - if (currentState->m_lineGrid == currentGrid) - continue; - currentGrid = currentState->m_lineGrid; - if (!currentGrid) - break; - if (currentGrid->style()->lineGrid() == block->style()->lineGrid()) { - m_lineGrid = currentGrid; - m_lineGridOffset = currentState->m_lineGridOffset; - return; - } - } - } - - // We didn't find an already-established grid with this identifier. Our render object establishes the grid. - m_lineGrid = block; - m_lineGridOffset = m_layoutOffset; -} - -void LayoutState::computeLineGridPaginationOrigin(RenderBox* renderer) -{ - // We need to cache a line grid pagination origin so that we understand how to reset the line grid - // at the top of each column. - // Get the current line grid and offset. - if (!lineGrid() || lineGrid()->style()->writingMode() != renderer->style()->writingMode()) - return; - - // Get the hypothetical line box used to establish the grid. - RootInlineBox* lineGridBox = lineGrid()->lineGridBox(); - if (!lineGridBox) - return; - - bool isHorizontalWritingMode = lineGrid()->isHorizontalWritingMode(); - - LayoutUnit lineGridBlockOffset = isHorizontalWritingMode ? lineGridOffset().height() : lineGridOffset().width(); - - // Now determine our position on the grid. Our baseline needs to be adjusted to the nearest baseline multiple - // as established by the line box. - // FIXME: Need to handle crazy line-box-contain values that cause the root line box to not be considered. I assume - // the grid should honor line-box-contain. - LayoutUnit gridLineHeight = lineGridBox->lineBottomWithLeading() - lineGridBox->lineTopWithLeading(); - if (!gridLineHeight) - return; - - LayoutUnit firstLineTopWithLeading = lineGridBlockOffset + lineGridBox->lineTopWithLeading(); - - if (isPaginated() && pageLogicalHeight()) { - LayoutUnit pageLogicalTop = renderer->isHorizontalWritingMode() ? m_pageOffset.height() : m_pageOffset.width(); - if (pageLogicalTop > firstLineTopWithLeading) { - // Shift to the next highest line grid multiple past the page logical top. Cache the delta - // between this new value and the page logical top as the pagination origin. - LayoutUnit remainder = roundToInt(pageLogicalTop - firstLineTopWithLeading) % roundToInt(gridLineHeight); - LayoutUnit paginationDelta = gridLineHeight - remainder; - if (isHorizontalWritingMode) - m_lineGridPaginationOrigin.setHeight(paginationDelta); - else - m_lineGridPaginationOrigin.setWidth(paginationDelta); - } - } -} - } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/LayoutState.h b/chromium/third_party/WebKit/Source/core/rendering/LayoutState.h index 16aa5b6ef36..8279bd3995b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/LayoutState.h +++ b/chromium/third_party/WebKit/Source/core/rendering/LayoutState.h @@ -33,89 +33,95 @@ namespace WebCore { -class RenderBlockFlow; +class ForceHorriblySlowRectMapping; class RenderBox; class RenderObject; -class RenderFlowThread; -class ShapeInsideInfo; +class RenderView; class LayoutState { WTF_MAKE_NONCOPYABLE(LayoutState); public: - LayoutState() - : m_clipped(false) - , m_isPaginated(false) - , m_pageLogicalHeightChanged(false) -#if !ASSERT_DISABLED - , m_layoutDeltaXSaturated(false) - , m_layoutDeltaYSaturated(false) -#endif - , m_columnInfo(0) - , m_lineGrid(0) - , m_next(0) - , m_shapeInsideInfo(0) - , m_pageLogicalHeight(0) -#ifndef NDEBUG - , m_renderer(0) -#endif - { - } + // Constructor for root LayoutState created by RenderView + LayoutState(LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged, RenderView&); + // Constructor for sub-tree Layout and RenderTableSections + explicit LayoutState(RenderObject& root); - LayoutState(LayoutState*, RenderBox*, const LayoutSize& offset, LayoutUnit pageHeight, bool pageHeightChanged, ColumnInfo*); - LayoutState(RenderObject*); + LayoutState(RenderBox&, const LayoutSize& offset, LayoutUnit pageLogicalHeight = 0, bool pageHeightLogicalChanged = false, ColumnInfo* = 0); - // LayoutState is allocated out of the rendering partition. - void* operator new(size_t); - void operator delete(void*); + ~LayoutState(); void clearPaginationInformation(); - bool isPaginatingColumns() const { return m_columnInfo && m_columnInfo->paginationUnit() == ColumnInfo::Column; } + bool isPaginatingColumns() const { return m_columnInfo; } bool isPaginated() const { return m_isPaginated; } + bool isClipped() const { return m_clipped; } // 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(RenderBox*, LayoutUnit childLogicalOffset) const; + LayoutUnit pageLogicalOffset(const RenderBox&, const LayoutUnit& childLogicalOffset) const; - void addForcedColumnBreak(RenderBox*, LayoutUnit childLogicalOffset); + void addForcedColumnBreak(const RenderBox&, const LayoutUnit& childLogicalOffset); + void addLayoutDelta(const LayoutSize& delta) + { + m_layoutDelta += delta; +#if ASSERT_ENABLED + m_layoutDeltaXSaturated |= m_layoutDelta.width() == LayoutUnit::max() || m_layoutDelta.width() == LayoutUnit::min(); + m_layoutDeltaYSaturated |= m_layoutDelta.height() == LayoutUnit::max() || m_layoutDelta.height() == LayoutUnit::min(); +#endif + } + + void setColumnInfo(ColumnInfo* columnInfo) { m_columnInfo = columnInfo; } + + const LayoutSize& layoutOffset() const { return m_layoutOffset; } + const LayoutSize& layoutDelta() const { return m_layoutDelta; } + const LayoutSize& pageOffset() const { return m_pageOffset; } LayoutUnit pageLogicalHeight() const { return m_pageLogicalHeight; } bool pageLogicalHeightChanged() const { return m_pageLogicalHeightChanged; } - RenderBlockFlow* lineGrid() const { return m_lineGrid; } - LayoutSize lineGridOffset() const { return m_lineGridOffset; } - LayoutSize lineGridPaginationOrigin() const { return m_lineGridPaginationOrigin; } + LayoutState* next() const { return m_next; } - LayoutSize layoutOffset() const { return m_layoutOffset; } + bool needsBlockDirectionLocationSetBeforeLayout() const { return m_isPaginated && m_pageLogicalHeight; } - bool needsBlockDirectionLocationSetBeforeLayout() const { return m_lineGrid || (m_isPaginated && m_pageLogicalHeight); } + ColumnInfo* columnInfo() const { return m_columnInfo; } - ShapeInsideInfo* shapeInsideInfo() const { return m_shapeInsideInfo; } + bool cachedOffsetsEnabled() const { return m_cachedOffsetsEnabled; } -#ifndef NDEBUG - RenderObject* renderer() const { return m_renderer; } + const LayoutRect& clipRect() const + { + ASSERT(m_cachedOffsetsEnabled); + return m_clipRect; + } + const LayoutSize& paintOffset() const + { + ASSERT(m_cachedOffsetsEnabled); + return m_paintOffset; + } + + + RenderObject& renderer() const { return m_renderer; } + +#if ASSERT_ENABLED + bool layoutDeltaXSaturated() const { return m_layoutDeltaXSaturated; } + bool layoutDeltaYSaturated() const { return m_layoutDeltaYSaturated; } #endif -private: - void propagateLineGridInfo(RenderBox*); - void establishLineGrid(RenderBlockFlow*); - void computeLineGridPaginationOrigin(RenderBox*); +private: + friend class ForceHorriblySlowRectMapping; -public: // Do not add anything apart from bitfields until after m_columnInfo. See https://bugs.webkit.org/show_bug.cgi?id=100173 bool m_clipped:1; bool m_isPaginated:1; // If our page height has changed, this will force all blocks to relayout. bool m_pageLogicalHeightChanged:1; -#if !ASSERT_DISABLED + + bool m_cachedOffsetsEnabled:1; +#if ASSERT_ENABLED bool m_layoutDeltaXSaturated:1; bool m_layoutDeltaYSaturated:1; #endif // If the enclosing pagination model is a column model, then this will store column information for easy retrieval/manipulation. ColumnInfo* m_columnInfo; - // The current line grid that we're snapping to and the offset of the start of the grid. - RenderBlockFlow* m_lineGrid; LayoutState* m_next; - ShapeInsideInfo* m_shapeInsideInfo; // FIXME: Distinguish between the layout clip rect and the paint clip rect which may be larger, // e.g., because of composited scrolling. @@ -134,12 +140,8 @@ public: LayoutUnit m_pageLogicalHeight; // The offset of the start of the first page in the nearest enclosing pagination model. LayoutSize m_pageOffset; - LayoutSize m_lineGridOffset; - LayoutSize m_lineGridPaginationOrigin; -#ifndef NDEBUG - RenderObject* m_renderer; -#endif + RenderObject& m_renderer; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/OrderIterator.cpp b/chromium/third_party/WebKit/Source/core/rendering/OrderIterator.cpp index 20926a576d5..3dfe9b65afc 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/OrderIterator.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/OrderIterator.cpp @@ -63,9 +63,9 @@ RenderBox* OrderIterator::next() m_isReset = false; } - m_currentChild = firstChildBox(); + m_currentChild = m_containerBox->firstChildBox(); } else { - m_currentChild = nextSiblingBox(); + m_currentChild = m_currentChild->nextSiblingBox(); } } while (!m_currentChild || m_currentChild->style()->order() != *m_orderValuesIterator); @@ -79,38 +79,11 @@ void OrderIterator::reset() m_isReset = true; } -RenderBox* OrderIterator::firstChildBox() -{ - if (m_children.isEmpty()) - return m_containerBox->firstChildBox(); - - m_childIndex = 0; - return m_children[0]; -} - -RenderBox* OrderIterator::nextSiblingBox() -{ - if (m_children.isEmpty()) - return m_currentChild->nextSiblingBox(); - - if (m_childIndex >= m_children.size() - 1) - return 0; - - return m_children[++m_childIndex]; -} - OrderIteratorPopulator::~OrderIteratorPopulator() { m_iterator.reset(); } -void OrderIteratorPopulator::storeChild(RenderBox* child) -{ - m_iterator.m_children.append(child); - - collectChild(child); -} - void OrderIteratorPopulator::collectChild(const RenderBox* child) { m_iterator.m_orderValues.insert(child->style()->order()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/OrderIterator.h b/chromium/third_party/WebKit/Source/core/rendering/OrderIterator.h index 2a019150a6b..d0ef6c04c8e 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/OrderIterator.h +++ b/chromium/third_party/WebKit/Source/core/rendering/OrderIterator.h @@ -53,15 +53,9 @@ public: void reset(); private: - RenderBox* firstChildBox(); - RenderBox* nextSiblingBox(); - - // If |m_children| is not empty, we will use it to iterate over this fixed subset. const RenderBox* m_containerBox; - Vector<RenderBox*> m_children; RenderBox* m_currentChild; - size_t m_childIndex; typedef std::set<int> OrderValues; OrderValues m_orderValues; @@ -79,7 +73,6 @@ public: ~OrderIteratorPopulator(); - void storeChild(RenderBox*); void collectChild(const RenderBox*); private: diff --git a/chromium/third_party/WebKit/Source/core/rendering/Pagination.cpp b/chromium/third_party/WebKit/Source/core/rendering/Pagination.cpp deleted file mode 100644 index 26822b03988..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/Pagination.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. 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" -#include "core/rendering/Pagination.h" - -#include "core/rendering/style/RenderStyle.h" - -namespace WebCore { - -void Pagination::setStylesForPaginationMode(Mode paginationMode, RenderStyle* style) -{ - if (paginationMode == Unpaginated) - return; - - switch (paginationMode) { - case LeftToRightPaginated: - style->setColumnAxis(HorizontalColumnAxis); - if (style->isHorizontalWritingMode()) - style->setColumnProgression(style->isLeftToRightDirection() ? NormalColumnProgression : ReverseColumnProgression); - else - style->setColumnProgression(style->isFlippedBlocksWritingMode() ? ReverseColumnProgression : NormalColumnProgression); - break; - case RightToLeftPaginated: - style->setColumnAxis(HorizontalColumnAxis); - if (style->isHorizontalWritingMode()) - style->setColumnProgression(style->isLeftToRightDirection() ? ReverseColumnProgression : NormalColumnProgression); - else - style->setColumnProgression(style->isFlippedBlocksWritingMode() ? NormalColumnProgression : ReverseColumnProgression); - break; - case TopToBottomPaginated: - style->setColumnAxis(VerticalColumnAxis); - if (style->isHorizontalWritingMode()) - style->setColumnProgression(style->isFlippedBlocksWritingMode() ? ReverseColumnProgression : NormalColumnProgression); - else - style->setColumnProgression(style->isLeftToRightDirection() ? NormalColumnProgression : ReverseColumnProgression); - break; - case BottomToTopPaginated: - style->setColumnAxis(VerticalColumnAxis); - if (style->isHorizontalWritingMode()) - style->setColumnProgression(style->isFlippedBlocksWritingMode() ? NormalColumnProgression : ReverseColumnProgression); - else - style->setColumnProgression(style->isLeftToRightDirection() ? ReverseColumnProgression : NormalColumnProgression); - break; - case Unpaginated: - ASSERT_NOT_REACHED(); - break; - } -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/Pagination.h b/chromium/third_party/WebKit/Source/core/rendering/Pagination.h deleted file mode 100644 index ce695f7bf14..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/Pagination.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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 Pagination_h -#define Pagination_h - -namespace WebCore { - -class RenderStyle; - -struct Pagination { - enum Mode { Unpaginated, LeftToRightPaginated, RightToLeftPaginated, TopToBottomPaginated, BottomToTopPaginated }; - - Pagination() - : mode(Unpaginated) - , behavesLikeColumns(false) - , pageLength(0) - , gap(0) - { - }; - - bool operator==(const Pagination& other) const - { - return mode == other.mode && behavesLikeColumns == other.behavesLikeColumns && pageLength == other.pageLength && gap == other.gap; - } - - bool operator!=(const Pagination& other) const - { - return mode != other.mode || behavesLikeColumns != other.behavesLikeColumns || pageLength != other.pageLength || gap != other.gap; - } - - Mode mode; - bool behavesLikeColumns; - unsigned pageLength; - unsigned gap; - - static void setStylesForPaginationMode(Mode, RenderStyle*); -}; - -} // namespace WebCore - -#endif diff --git a/chromium/third_party/WebKit/Source/core/rendering/PaintInfo.h b/chromium/third_party/WebKit/Source/core/rendering/PaintInfo.h index be99ec39407..50b6463a1a4 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/PaintInfo.h +++ b/chromium/third_party/WebKit/Source/core/rendering/PaintInfo.h @@ -40,7 +40,6 @@ namespace WebCore { class RenderInline; class RenderLayerModelObject; class RenderObject; -class RenderRegion; class RenderWidget; typedef HashMap<RenderWidget*, IntRect> OverlapTestRequestMap; @@ -51,14 +50,13 @@ typedef HashMap<RenderWidget*, IntRect> OverlapTestRequestMap; */ struct PaintInfo { PaintInfo(GraphicsContext* newContext, const IntRect& newRect, PaintPhase newPhase, PaintBehavior newPaintBehavior, - RenderObject* newPaintingRoot = 0, RenderRegion* region = 0, ListHashSet<RenderInline*>* newOutlineObjects = 0, + RenderObject* newPaintingRoot = 0, ListHashSet<RenderInline*>* newOutlineObjects = 0, OverlapTestRequestMap* overlapTestRequests = 0, const RenderLayerModelObject* newPaintContainer = 0) : context(newContext) , rect(newRect) , phase(newPhase) , paintBehavior(newPaintBehavior) , paintingRoot(newPaintingRoot) - , renderRegion(region) , overlapTestRequests(overlapTestRequests) , m_paintContainer(newPaintContainer) , m_outlineObjects(newOutlineObjects) @@ -87,9 +85,9 @@ struct PaintInfo { bool skipRootBackground() const { return paintBehavior & PaintBehaviorSkipRootBackground; } bool paintRootBackgroundOnly() const { return paintBehavior & PaintBehaviorRootBackgroundOnly; } - void applyTransform(const AffineTransform& localToAncestorTransform) + void applyTransform(const AffineTransform& localToAncestorTransform, bool identityStatusUnknown = true) { - if (localToAncestorTransform.isIdentity()) + if (identityStatusUnknown && localToAncestorTransform.isIdentity()) return; context->concatCTM(localToAncestorTransform); @@ -97,7 +95,10 @@ struct PaintInfo { if (rect == infiniteRect()) return; - rect = localToAncestorTransform.inverse().mapRect(rect); + if (localToAncestorTransform.isInvertible()) + rect = localToAncestorTransform.inverse().mapRect(rect); + else + rect.setSize(IntSize(0, 0)); } static IntRect infiniteRect() { return IntRect(LayoutRect::infiniteRect()); } @@ -112,7 +113,6 @@ struct PaintInfo { PaintPhase phase; PaintBehavior paintBehavior; RenderObject* paintingRoot; // used to draw just one element and its visual kids - RenderRegion* renderRegion; OverlapTestRequestMap* overlapTestRequests; private: diff --git a/chromium/third_party/WebKit/Source/core/rendering/PartialLayoutState.h b/chromium/third_party/WebKit/Source/core/rendering/PartialLayoutState.h deleted file mode 100644 index 1ac7a328f71..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/PartialLayoutState.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2013 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: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT - * OWNER 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 PartialLayoutState_h -#define PartialLayoutState_h - -#include "core/rendering/RenderObject.h" - -namespace WebCore { - -class PartialLayoutState { - friend class PartialLayoutDisabler; -public: - PartialLayoutState() - : m_shouldStop(false) - , m_stopAtRenderer(0) - , m_disableCount(0) - { - } - - // True if we plan to do a partial layout, or are in the process of stopping a partial layout. - bool isPartialLayout() const { return m_stopAtRenderer || m_shouldStop; } - - bool isStopping() const { return m_shouldStop; } - bool checkPartialLayoutComplete(const RenderObject*); - void setStopAtRenderer(const RenderObject* renderer) { m_stopAtRenderer = renderer; } - void reset() { m_shouldStop = false; m_stopAtRenderer = 0; } - -private: - void disable() { ASSERT(!m_shouldStop); m_disableCount++; } - void enable() { ASSERT(m_disableCount > 0); m_disableCount--; } - const RenderObject* stopAtRenderer() const { return m_disableCount > 0 ? 0 : m_stopAtRenderer; } - - bool m_shouldStop; - const RenderObject* m_stopAtRenderer; - int m_disableCount; -}; - -inline bool PartialLayoutState::checkPartialLayoutComplete(const RenderObject* renderer) -{ - if (m_shouldStop) - return true; - - if (renderer == stopAtRenderer()) { - m_shouldStop = true; - m_stopAtRenderer = 0; - return true; - } - - return false; -} - -class PartialLayoutDisabler { - WTF_MAKE_NONCOPYABLE(PartialLayoutDisabler); -public: - PartialLayoutDisabler(PartialLayoutState& partialLayout, bool disable = true) - : m_partialLayout(partialLayout) - , m_disable(disable) - { - if (m_disable) - m_partialLayout.disable(); - } - - ~PartialLayoutDisabler() - { - if (m_disable) - m_partialLayout.enable(); - } -private: - PartialLayoutState& m_partialLayout; - bool m_disable; -}; - -} // namespace WebCore - -#endif // PartialLayoutState_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderApplet.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderApplet.cpp index be4de73f89d..38d0e4c938f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderApplet.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderApplet.cpp @@ -22,6 +22,7 @@ #include "config.h" #include "core/rendering/RenderApplet.h" +#include "core/frame/UseCounter.h" #include "core/html/HTMLAppletElement.h" namespace WebCore { @@ -30,6 +31,7 @@ RenderApplet::RenderApplet(HTMLAppletElement* applet) : RenderEmbeddedObject(applet) { setInline(true); + UseCounter::count(document(), UseCounter::HTMLAppletElement); } RenderApplet::~RenderApplet() diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderApplet.h b/chromium/third_party/WebKit/Source/core/rendering/RenderApplet.h index 3a0f7af28b2..9f740f404db 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderApplet.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderApplet.h @@ -34,7 +34,7 @@ public: virtual ~RenderApplet(); private: - virtual const char* renderName() const { return "RenderApplet"; } + virtual const char* renderName() const OVERRIDE { return "RenderApplet"; } }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderBR.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderBR.cpp index ea74001d6a7..e928cceceb7 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderBR.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderBR.cpp @@ -35,7 +35,6 @@ static PassRefPtr<StringImpl> newlineString() RenderBR::RenderBR(Node* node) : RenderText(node, newlineString()) - , m_lineHeight(-1) { } @@ -45,22 +44,13 @@ RenderBR::~RenderBR() int RenderBR::lineHeight(bool firstLine) const { - if (firstLine && document().styleEngine()->usesFirstLineRules()) { - RenderStyle* s = style(firstLine); - if (s != style()) - return s->computedLineHeight(view()); - } - - if (m_lineHeight == -1) - m_lineHeight = style()->computedLineHeight(view()); - - return m_lineHeight; + RenderStyle* s = style(firstLine && document().styleEngine()->usesFirstLineRules()); + return s->computedLineHeight(); } void RenderBR::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderText::styleDidChange(diff, oldStyle); - m_lineHeight = -1; } int RenderBR::caretMinOffset() const diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderBR.h b/chromium/third_party/WebKit/Source/core/rendering/RenderBR.h index 62d1a53479e..ff69d3a87a2 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderBR.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderBR.h @@ -29,35 +29,30 @@ */ namespace WebCore { -class Position; - class RenderBR FINAL : public RenderText { public: explicit RenderBR(Node*); virtual ~RenderBR(); - virtual const char* renderName() const { return "RenderBR"; } + virtual const char* renderName() const OVERRIDE { return "RenderBR"; } - virtual LayoutRect selectionRectForRepaint(const RenderLayerModelObject* /*repaintContainer*/, bool /*clipToVisibleContent*/) OVERRIDE { return LayoutRect(); } + virtual LayoutRect selectionRectForPaintInvalidation(const RenderLayerModelObject* /*paintInvalidationContainer*/, bool /*clipToVisibleContent*/) OVERRIDE { return LayoutRect(); } - virtual float width(unsigned /*from*/, unsigned /*len*/, const Font&, float /*xPos*/, HashSet<const SimpleFontData*>* = 0 /*fallbackFonts*/ , GlyphOverflow* = 0) const { return 0; } - virtual float width(unsigned /*from*/, unsigned /*len*/, float /*xpos*/, bool = false /*firstLine*/, HashSet<const SimpleFontData*>* = 0 /*fallbackFonts*/, GlyphOverflow* = 0) const { return 0; } + virtual float width(unsigned /*from*/, unsigned /*len*/, const Font&, float /*xPos*/, TextDirection, HashSet<const SimpleFontData*>* = 0 /*fallbackFonts*/ , GlyphOverflow* = 0) const OVERRIDE { return 0; } + virtual float width(unsigned /*from*/, unsigned /*len*/, float /*xpos*/, TextDirection, bool = false /*firstLine*/, HashSet<const SimpleFontData*>* = 0 /*fallbackFonts*/, GlyphOverflow* = 0) const OVERRIDE { return 0; } int lineHeight(bool firstLine) const; // overrides - virtual bool isBR() const { return true; } + virtual bool isBR() const OVERRIDE { return true; } - virtual int caretMinOffset() const; - virtual int caretMaxOffset() const; + virtual int caretMinOffset() const OVERRIDE; + virtual int caretMaxOffset() const OVERRIDE; virtual PositionWithAffinity positionForPoint(const LayoutPoint&) OVERRIDE FINAL; protected: - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - -private: - mutable int m_lineHeight; + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderBR, isBR()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderBlock.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderBlock.cpp index 84c790b6ab7..e7cf72c32b3 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderBlock.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderBlock.cpp @@ -24,7 +24,7 @@ #include "config.h" #include "core/rendering/RenderBlock.h" -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/accessibility/AXObjectCache.h" #include "core/dom/Document.h" #include "core/dom/Element.h" @@ -33,8 +33,8 @@ #include "core/editing/Editor.h" #include "core/editing/FrameSelection.h" #include "core/fetch/ResourceLoadPriorityOptimizer.h" -#include "core/frame/Frame.h" #include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/page/Page.h" #include "core/frame/Settings.h" #include "core/rendering/FastTextAutosizer.h" @@ -43,18 +43,19 @@ #include "core/rendering/HitTestResult.h" #include "core/rendering/InlineIterator.h" #include "core/rendering/InlineTextBox.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/LayoutRepainter.h" #include "core/rendering/PaintInfo.h" #include "core/rendering/RenderCombineText.h" #include "core/rendering/RenderDeprecatedFlexibleBox.h" #include "core/rendering/RenderFlexibleBox.h" +#include "core/rendering/RenderFlowThread.h" +#include "core/rendering/RenderGrid.h" #include "core/rendering/RenderInline.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderMarquee.h" -#include "core/rendering/RenderNamedFlowThread.h" #include "core/rendering/RenderRegion.h" #include "core/rendering/RenderTableCell.h" +#include "core/rendering/RenderTextControl.h" #include "core/rendering/RenderTextFragment.h" #include "core/rendering/RenderTheme.h" #include "core/rendering/RenderView.h" @@ -63,6 +64,7 @@ #include "core/rendering/style/RenderStyle.h" #include "platform/geometry/FloatQuad.h" #include "platform/geometry/TransformState.h" +#include "platform/graphics/GraphicsContextCullSaver.h" #include "platform/graphics/GraphicsContextStateSaver.h" #include "wtf/StdLibExtras.h" #include "wtf/TemporaryChange.h" @@ -82,7 +84,14 @@ struct SameSizeAsRenderBlock : public RenderBox { uint32_t bitfields; }; +struct SameSizeAsRenderBlockRareData { + int paginationStrut; + int pageLogicalOffset; + uint32_t bitfields; +}; + COMPILE_ASSERT(sizeof(RenderBlock) == sizeof(SameSizeAsRenderBlock), RenderBlock_should_stay_small); +COMPILE_ASSERT(sizeof(RenderBlock::RenderBlockRareData) == sizeof(SameSizeAsRenderBlockRareData), RenderBlockRareData_should_stay_small); typedef WTF::HashMap<const RenderBox*, OwnPtr<ColumnInfo> > ColumnInfoMap; static ColumnInfoMap* gColumnInfoMap = 0; @@ -108,6 +117,8 @@ class OverflowEventDispatcher { public: OverflowEventDispatcher(const RenderBlock* block) : m_block(block) + , m_hadHorizontalLayoutOverflow(false) + , m_hadVerticalLayoutOverflow(false) { m_shouldDispatchEvent = !m_block->isAnonymous() && m_block->hasOverflowClip() && m_block->document().hasListenerType(Document::OVERFLOWCHANGED_LISTENER); if (m_shouldDispatchEvent) { @@ -130,7 +141,7 @@ public: if (!horizontalLayoutOverflowChanged && !verticalLayoutOverflowChanged) return; - RefPtr<OverflowEvent> event = OverflowEvent::create(horizontalLayoutOverflowChanged, hasHorizontalLayoutOverflow, verticalLayoutOverflowChanged, hasVerticalLayoutOverflow); + RefPtrWillBeRawPtr<OverflowEvent> event = OverflowEvent::create(horizontalLayoutOverflowChanged, hasHorizontalLayoutOverflow, verticalLayoutOverflowChanged, hasVerticalLayoutOverflow); event->setTarget(m_block->node()); m_block->document().enqueueAnimationFrameEvent(event.release()); } @@ -144,12 +155,12 @@ private: RenderBlock::RenderBlock(ContainerNode* node) : RenderBox(node) - , m_lineHeight(-1) , m_hasMarginBeforeQuirk(false) , m_hasMarginAfterQuirk(false) , m_beingDestroyed(false) , m_hasMarkupTruncation(false) , m_hasBorderOrPaddingLogicalWidthChanged(false) + , m_hasOnlySelfCollapsingChildren(false) { setChildrenInline(true); } @@ -174,8 +185,11 @@ static void removeBlockFromDescendantAndContainerMaps(RenderBlock* block, Tracke static void appendImageIfNotNull(Vector<ImageResource*>& imageResources, const StyleImage* styleImage) { - if (styleImage && styleImage->cachedImage()) - imageResources.append(styleImage->cachedImage()); + if (styleImage && styleImage->cachedImage()) { + ImageResource* imageResource = styleImage->cachedImage(); + if (imageResource && !imageResource->isLoaded()) + imageResources.append(styleImage->cachedImage()); + } } static void appendLayers(Vector<ImageResource*>& images, const FillLayer* styleLayer) @@ -185,6 +199,25 @@ static void appendLayers(Vector<ImageResource*>& images, const FillLayer* styleL } } +static void appendImagesFromStyle(Vector<ImageResource*>& images, RenderStyle& blockStyle) +{ + appendLayers(images, blockStyle.backgroundLayers()); + appendLayers(images, blockStyle.maskLayers()); + + const ContentData* contentData = blockStyle.contentData(); + if (contentData && contentData->isImage()) { + const ImageContentData* imageContentData = static_cast<const ImageContentData*>(contentData); + appendImageIfNotNull(images, imageContentData->image()); + } + if (blockStyle.boxReflect()) + appendImageIfNotNull(images, blockStyle.boxReflect()->mask().image()); + appendImageIfNotNull(images, blockStyle.listStyleImage()); + appendImageIfNotNull(images, blockStyle.borderImageSource()); + appendImageIfNotNull(images, blockStyle.maskBoxImageSource()); + if (blockStyle.shapeOutside()) + appendImageIfNotNull(images, blockStyle.shapeOutside()->image()); +} + RenderBlock::~RenderBlock() { if (hasColumns()) @@ -240,25 +273,27 @@ void RenderBlock::willBeDestroyed() if (UNLIKELY(gDelayedUpdateScrollInfoSet != 0)) gDelayedUpdateScrollInfoSet->remove(this); - FastTextAutosizer* textAutosizer = document().fastTextAutosizer(); - if (textAutosizer) + if (FastTextAutosizer* textAutosizer = document().fastTextAutosizer()) textAutosizer->destroy(this); RenderBox::willBeDestroyed(); } -void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) +void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle& newStyle) { RenderStyle* oldStyle = style(); - setReplaced(newStyle->isDisplayInlineType()); + setReplaced(newStyle.isDisplayInlineType()); - if (oldStyle && parent() && diff == StyleDifferenceLayout && oldStyle->position() != newStyle->position()) { - if (newStyle->position() == StaticPosition) + if (oldStyle && parent()) { + bool oldStyleIsContainer = oldStyle->position() != StaticPosition || oldStyle->hasTransformRelatedProperty(); + bool newStyleIsContainer = newStyle.position() != StaticPosition || newStyle.hasTransformRelatedProperty(); + + if (oldStyleIsContainer && !newStyleIsContainer) { // Clear our positioned objects list. Our absolutely positioned descendants will be // inserted into our containing block's positioned objects list during layout. removePositionedObjects(0, NewContainingBlock); - else if (oldStyle->position() == StaticPosition) { + } else if (!oldStyleIsContainer && newStyleIsContainer) { // Remove our absolutely positioned descendants from their current containing block. // They will be inserted into our positioned objects list during layout. RenderObject* cb = parent(); @@ -298,8 +333,6 @@ void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldSty RenderStyle* newStyle = style(); - updateShapeInsideInfoAfterStyleChange(newStyle->resolvedShapeInside(), oldStyle ? oldStyle->resolvedShapeInside() : RenderStyle::initialShapeInside()); - if (!isAnonymousBlock()) { // Ensure that all of our continuation blocks pick up the new style. for (RenderBlock* currCont = blockElementContinuation(); currCont; currCont = currCont->blockElementContinuation()) { @@ -310,16 +343,63 @@ void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldSty } } - FastTextAutosizer* textAutosizer = document().fastTextAutosizer(); - if (textAutosizer) + if (FastTextAutosizer* textAutosizer = document().fastTextAutosizer()) textAutosizer->record(this); propagateStyleToAnonymousChildren(true); - m_lineHeight = -1; // It's possible for our border/padding to change, but for the overall logical width of the block to // end up being the same. We keep track of this change so in layoutBlock, we can know to set relayoutChildren=true. - m_hasBorderOrPaddingLogicalWidthChanged = oldStyle && diff == StyleDifferenceLayout && needsLayout() && borderOrPaddingLogicalWidthChanged(oldStyle, newStyle); + m_hasBorderOrPaddingLogicalWidthChanged = oldStyle && diff.needsFullLayout() && needsLayout() && borderOrPaddingLogicalWidthChanged(oldStyle, newStyle); + + // If the style has unloaded images, want to notify the ResourceLoadPriorityOptimizer so that + // network priorities can be set. + Vector<ImageResource*> images; + appendImagesFromStyle(images, *newStyle); + if (images.isEmpty()) + ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->removeRenderObject(this); + else + ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->addRenderObject(this); +} + +void RenderBlock::invalidateTreeAfterLayout(const RenderLayerModelObject& invalidationContainer) +{ + // Note, we don't want to early out here using shouldCheckForInvalidationAfterLayout as + // we have to make sure we go through any positioned objects as they won't be seen in + // the normal tree walk. + + if (shouldCheckForPaintInvalidationAfterLayout()) + RenderBox::invalidateTreeAfterLayout(invalidationContainer); + + // Take care of positioned objects. This is required as LayoutState keeps a single clip rect. + if (TrackedRendererListHashSet* positionedObjects = this->positionedObjects()) { + TrackedRendererListHashSet::iterator end = positionedObjects->end(); + LayoutState state(*this, isTableRow() ? LayoutSize() : locationOffset()); + for (TrackedRendererListHashSet::iterator it = positionedObjects->begin(); it != end; ++it) { + RenderBox* box = *it; + + // One of the renderers we're skipping over here may be the child's repaint container, + // so we can't pass our own repaint container along. + const RenderLayerModelObject& repaintContainerForChild = *box->containerForPaintInvalidation(); + + // If the positioned renderer is absolutely positioned and it is inside + // a relatively positioend inline element, we need to account for + // the inline elements position in LayoutState. + if (box->style()->position() == AbsolutePosition) { + RenderObject* container = box->container(&repaintContainerForChild, 0); + if (container->isInFlowPositioned() && container->isRenderInline()) { + // FIXME: We should be able to use layout-state for this. + // Currently, we will place absolutly positioned elements inside + // relatively positioned inline blocks in the wrong location. crbug.com/371485 + ForceHorriblySlowRectMapping slowRectMapping(*this); + box->invalidateTreeAfterLayout(repaintContainerForChild); + continue; + } + } + + box->invalidateTreeAfterLayout(repaintContainerForChild); + } + } } RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild) @@ -458,7 +538,7 @@ RenderBlockFlow* RenderBlock::containingColumnsBlock(bool allowAnonymousColumnBl { RenderBlock* firstChildIgnoringAnonymousWrappers = 0; for (RenderObject* curr = this; curr; curr = curr->parent()) { - if (!curr->isRenderBlock() || curr->isFloatingOrOutOfFlowPositioned() || curr->isTableCell() || curr->isRoot() || curr->isRenderView() || curr->hasOverflowClip() + if (!curr->isRenderBlock() || curr->isFloatingOrOutOfFlowPositioned() || curr->isTableCell() || curr->isDocumentElement() || curr->isRenderView() || curr->hasOverflowClip() || curr->isInlineBlockOrInlineTable()) return 0; @@ -622,9 +702,9 @@ void RenderBlock::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox, // Always just do a full layout in order to ensure that line boxes (especially wrappers for images) // get deleted properly. Because objects moves from the pre block into the post block, we want to // make new line boxes instead of leaving the old line boxes around. - pre->setNeedsLayoutAndPrefWidthsRecalc(); - block->setNeedsLayoutAndPrefWidthsRecalc(); - post->setNeedsLayoutAndPrefWidthsRecalc(); + pre->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); + block->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); + post->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlockFlow* newBlockBox, RenderObject* newChild) @@ -672,10 +752,10 @@ void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, R // get deleted properly. Because objects moved from the pre block into the post block, we want to // make new line boxes instead of leaving the old line boxes around. if (pre) - pre->setNeedsLayoutAndPrefWidthsRecalc(); - block->setNeedsLayoutAndPrefWidthsRecalc(); + pre->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); + block->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); if (post) - post->setNeedsLayoutAndPrefWidthsRecalc(); + post->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } RenderBlockFlow* RenderBlock::columnsBlockForSpanningElement(RenderObject* newChild) @@ -725,7 +805,7 @@ void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, || beforeChildAnonymousContainer->isRenderFullScreenPlaceholder() ) { // Insert the child into the anonymous block box instead of here. - if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild) + if (newChild->isInline() || newChild->isFloatingOrOutOfFlowPositioned() || beforeChild->parent()->slowFirstChild() != beforeChild) beforeChild->parent()->addChild(newChild, beforeChild); else addChild(newChild, beforeChild->parent()); @@ -751,7 +831,7 @@ void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, } // Check for a spanning element in columns. - if (gColumnFlowSplitEnabled) { + if (gColumnFlowSplitEnabled && !document().regionBasedColumnsEnabled()) { RenderBlockFlow* columnsBlockAncestor = columnsBlockForSpanningElement(newChild); if (columnsBlockAncestor) { TemporaryChange<bool> columnFlowSplitEnabled(gColumnFlowSplitEnabled, false); @@ -886,19 +966,6 @@ void RenderBlock::deleteLineBoxTree() cache->recomputeIsIgnored(this); } -RootInlineBox* RenderBlock::createAndAppendRootInlineBox() -{ - RootInlineBox* rootBox = createRootInlineBox(); - m_lineBoxes.appendLineBox(rootBox); - - if (UNLIKELY(AXObjectCache::accessibilityEnabled()) && m_lineBoxes.firstLineBox() == rootBox) { - if (AXObjectCache* cache = document().existingAXObjectCache()) - cache->recomputeIsIgnored(this); - } - - return rootBox; -} - void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) { // makeChildrenNonInline takes a block whose children are *all* inline and it @@ -938,7 +1005,7 @@ void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) ASSERT(!c->isInline()); #endif - repaint(); + paintInvalidationForWholeRenderer(); } void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child) @@ -986,6 +1053,10 @@ void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child) // Remove all the information in the flow thread associated with the leftover anonymous block. child->removeFromRenderFlowThread(); + // RenderGrid keeps track of its children, we must notify it about changes in the tree. + if (child->parent()->isRenderGrid()) + toRenderGrid(child->parent())->dirtyGrid(); + child->setParent(0); child->setPreviousSibling(0); child->setNextSibling(0); @@ -1021,7 +1092,7 @@ void RenderBlock::collapseAnonymousBlockChild(RenderBlock* parent, RenderBlock* // destroyed. See crbug.com/282088 if (child->beingDestroyed()) return; - parent->setNeedsLayoutAndPrefWidthsRecalc(); + parent->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); parent->setChildrenInline(child->childrenInline()); RenderObject* nextSibling = child->nextSibling(); @@ -1033,8 +1104,6 @@ void RenderBlock::collapseAnonymousBlockChild(RenderBlock* parent, RenderBlock* // Explicitly delete the child's line box tree, or the special anonymous // block handling in willBeDestroyed will cause problems. child->deleteLineBoxTree(); - if (childFlowThread && childFlowThread->isRenderNamedFlowThread()) - toRenderNamedFlowThread(childFlowThread)->removeFlowChildInfo(child); child->destroy(); } @@ -1057,9 +1126,9 @@ void RenderBlock::removeChild(RenderObject* oldChild) RenderObject* next = oldChild->nextSibling(); bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, prev, next); if (canMergeAnonymousBlocks && prev && next) { - prev->setNeedsLayoutAndPrefWidthsRecalc(); - RenderBlock* nextBlock = toRenderBlock(next); - RenderBlock* prevBlock = toRenderBlock(prev); + prev->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); + RenderBlockFlow* nextBlock = toRenderBlockFlow(next); + RenderBlockFlow* prevBlock = toRenderBlockFlow(prev); if (prev->childrenInline() != next->childrenInline()) { RenderBlock* inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock; @@ -1079,7 +1148,7 @@ void RenderBlock::removeChild(RenderObject* oldChild) // Now just put the inlineChildrenBlock inside the blockChildrenBlock. blockChildrenBlock->children()->insertChildNode(blockChildrenBlock, inlineChildrenBlock, prev == inlineChildrenBlock ? blockChildrenBlock->firstChild() : 0, inlineChildrenBlockHasLayer || blockChildrenBlock->hasLayer()); - next->setNeedsLayoutAndPrefWidthsRecalc(); + next->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); // inlineChildrenBlock got reparented to blockChildrenBlock, so it is no longer a child // of "this". we null out prev or next so that is not used later in the function. @@ -1128,7 +1197,7 @@ void RenderBlock::removeChild(RenderObject* oldChild) // we need to remove ourself and fix the continuation chain. if (!beingDestroyed() && isAnonymousBlockContinuation() && !oldChild->isListMarker()) { RenderObject* containingBlockIgnoringAnonymous = containingBlock(); - while (containingBlockIgnoringAnonymous && containingBlockIgnoringAnonymous->isAnonymousBlock()) + while (containingBlockIgnoringAnonymous && containingBlockIgnoringAnonymous->isAnonymous()) containingBlockIgnoringAnonymous = containingBlockIgnoringAnonymous->containingBlock(); for (RenderObject* curr = this; curr; curr = curr->previousInPreOrder(containingBlockIgnoringAnonymous)) { if (curr->virtualContinuation() != this) @@ -1160,6 +1229,20 @@ bool RenderBlock::isSelfCollapsingBlock() const // (c) have border/padding, // (d) have a min-height // (e) have specified that one of our margins can't collapse using a CSS extension + // (f) establish a new block formatting context. + + // The early exit must be done before we check for clean layout. + // We should be able to give a quick answer if the box is a relayout boundary. + // Being a relayout boundary implies a block formatting context, and also + // our internal layout shouldn't affect our container in any way. + if (createsBlockFormattingContext()) + return false; + + // Placeholder elements are not laid out until the dimensions of their parent text control are known, so they + // don't get layout until their parent has had layout - this is unique in the layout tree and means + // when we call isSelfCollapsingBlock on them we find that they still need layout. + ASSERT(!needsLayout() || (node() && node()->isElementNode() && toElement(node())->shadowPseudoId() == "-webkit-input-placeholder")); + if (logicalHeight() > 0 || isTable() || borderAndPaddingLogicalHeight() || style()->logicalMinHeight().isPositive() @@ -1186,6 +1269,8 @@ bool RenderBlock::isSelfCollapsingBlock() const // Whether or not we collapse is dependent on whether all our normal flow children // are also self-collapsing. + if (m_hasOnlySelfCollapsingChildren) + return true; for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { if (child->isFloatingOrOutOfFlowPositioned()) continue; @@ -1248,7 +1333,6 @@ void RenderBlock::updateScrollInfoAfterLayout() void RenderBlock::layout() { OverflowEventDispatcher dispatcher(this); - LayoutRectRecorder recorder(*this); // Update our first letter info now. updateFirstLetter(); @@ -1257,9 +1341,6 @@ void RenderBlock::layout() // layoutBlock(). layoutBlock(false); - if (frameView()->partialLayout().isStopping()) - return; - // It's safe to check for control clip here, since controls can never be table cells. // If we have a lightweight clip, there can never be any overflow from children. if (hasControlClip() && m_overflow) @@ -1268,42 +1349,13 @@ void RenderBlock::layout() invalidateBackgroundObscurationStatus(); } -void RenderBlock::didLayout(ResourceLoadPriorityOptimizer& optimizer) -{ - RenderBox::didLayout(optimizer); - updateStyleImageLoadingPriorities(optimizer); -} - -void RenderBlock::didScroll(ResourceLoadPriorityOptimizer& optimizer) -{ - RenderBox::didScroll(optimizer); - updateStyleImageLoadingPriorities(optimizer); -} - -void RenderBlock::updateStyleImageLoadingPriorities(ResourceLoadPriorityOptimizer& optimizer) +bool RenderBlock::updateImageLoadingPriorities() { - RenderStyle* blockStyle = style(); - if (!blockStyle) - return; - Vector<ImageResource*> images; - - appendLayers(images, blockStyle->backgroundLayers()); - appendLayers(images, blockStyle->maskLayers()); - - const ContentData* contentData = blockStyle->contentData(); - if (contentData && contentData->isImage()) { - const ImageContentData* imageContentData = static_cast<const ImageContentData*>(contentData); - appendImageIfNotNull(images, imageContentData->image()); - } - if (blockStyle->boxReflect()) - appendImageIfNotNull(images, blockStyle->boxReflect()->mask().image()); - appendImageIfNotNull(images, blockStyle->listStyleImage()); - appendImageIfNotNull(images, blockStyle->borderImageSource()); - appendImageIfNotNull(images, blockStyle->maskBoxImageSource()); + appendImagesFromStyle(images, *style()); if (images.isEmpty()) - return; + return false; LayoutRect viewBounds = viewRect(); LayoutRect objectBounds = absoluteContentBox(); @@ -1318,165 +1370,16 @@ void RenderBlock::updateStyleImageLoadingPriorities(ResourceLoadPriorityOptimize ResourceLoadPriorityOptimizer::VisibilityStatus status = isVisible ? ResourceLoadPriorityOptimizer::Visible : ResourceLoadPriorityOptimizer::NotVisible; - for (Vector<ImageResource*>::iterator it = images.begin(), end = images.end(); it != end; ++it) - optimizer.notifyImageResourceVisibility(*it, status); -} - -void RenderBlock::relayoutShapeDescendantIfMoved(RenderBlock* child, LayoutSize offset) -{ - LayoutUnit left = isHorizontalWritingMode() ? offset.width() : offset.height(); - if (!left || !child || child->shapeInsideInfo() || !layoutShapeInsideInfo()) - return; - // Propagate layout markers only up to the child, as we are still in the middle - // of a layout pass - child->setNormalChildNeedsLayout(true); - child->markShapeInsideDescendantsForLayout(); - child->layoutIfNeeded(); -} - -ShapeInsideInfo* RenderBlock::layoutShapeInsideInfo() const -{ - if (ShapeInsideInfo* shapeInsideInfo = view()->layoutState()->shapeInsideInfo()) - return shapeInsideInfo; - - RenderFlowThread* flowThread = flowThreadContainingBlock(); - if (allowsShapeInsideInfoSharing(flowThread)) { - LayoutUnit lineHeight = this->lineHeight(false, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); - // regionAtBlockOffset returns regions like an array first={0,N-1}, second={N,M-1}, ... - LayoutUnit offset = logicalHeight() + lineHeight - LayoutUnit(1); - RenderRegion* region = regionAtBlockOffset(offset); - if (region && region->logicalHeight()) - return region->shapeInsideInfo(); - } - - return 0; -} - -LayoutSize RenderBlock::logicalOffsetFromShapeAncestorContainer(const RenderBlock* container) const -{ - const RenderBlock* currentBlock = this; - LayoutRect blockRect(currentBlock->borderBoxRect()); - while (currentBlock && !currentBlock->isRenderFlowThread() && currentBlock != container) { - RenderBlock* containerBlock = currentBlock->containingBlock(); - ASSERT(containerBlock); - if (!containerBlock) - return LayoutSize(); - - if (containerBlock->style()->writingMode() != currentBlock->style()->writingMode()) { - // We have to put the block rect in container coordinates - // and we have to take into account both the container and current block flipping modes - // Bug: Flipping inline and block directions at the same time will not work, - // as one of the flipped dimensions will not yet have been set to its final size - if (containerBlock->style()->isFlippedBlocksWritingMode()) { - if (containerBlock->isHorizontalWritingMode()) - blockRect.setY(currentBlock->height() - blockRect.maxY()); - else - blockRect.setX(currentBlock->width() - blockRect.maxX()); - } - currentBlock->flipForWritingMode(blockRect); - } - - blockRect.moveBy(currentBlock->location()); - currentBlock = containerBlock; - } - - LayoutSize result = isHorizontalWritingMode() ? LayoutSize(blockRect.x(), blockRect.y()) : LayoutSize(blockRect.y(), blockRect.x()); - return result; -} - -void RenderBlock::imageChanged(WrappedImagePtr image, const IntRect*) -{ - RenderBox::imageChanged(image); - - if (!parent() || !everHadLayout()) - return; - - ShapeValue* shapeValue = style()->shapeInside(); - if (shapeValue && shapeValue->image() && shapeValue->image()->data() == image) { - ShapeInsideInfo* shapeInsideInfo = ensureShapeInsideInfo(); - shapeInsideInfo->dirtyShapeSize(); - markShapeInsideDescendantsForLayout(); - } - - ShapeValue* shapeOutsideValue = style()->shapeOutside(); - if (isFloating() && shapeOutsideValue && shapeOutsideValue->image() && shapeOutsideValue->image()->data() == image) - parent()->setNeedsLayoutAndPrefWidthsRecalc(); -} - -void RenderBlock::updateShapeInsideInfoAfterStyleChange(const ShapeValue* shapeInside, const ShapeValue* oldShapeInside) -{ - // FIXME: A future optimization would do a deep comparison for equality. - if (shapeInside == oldShapeInside) - return; - - if (shapeInside) { - ShapeInsideInfo* shapeInsideInfo = ensureShapeInsideInfo(); - shapeInsideInfo->dirtyShapeSize(); - } else { - setShapeInsideInfo(nullptr); - markShapeInsideDescendantsForLayout(); - } -} - -static inline bool shapeInfoRequiresRelayout(const RenderBlock* block) -{ - ShapeInsideInfo* info = block->shapeInsideInfo(); - if (info) - info->setNeedsLayout(info->shapeSizeDirty()); - else - info = block->layoutShapeInsideInfo(); - return info && info->needsLayout(); -} - -bool RenderBlock::updateRegionsAndShapesLogicalSize(RenderFlowThread* flowThread) -{ - if (!flowThread && !shapeInsideInfo()) - return shapeInfoRequiresRelayout(this); - - LayoutUnit oldHeight = logicalHeight(); - LayoutUnit oldTop = logicalTop(); - - // Compute the maximum logical height content may cause this block to expand to - // FIXME: These should eventually use the const computeLogicalHeight rather than updateLogicalHeight - setLogicalHeight(RenderFlowThread::maxLogicalHeight()); - updateLogicalHeight(); - - computeShapeSize(); - - // Set our start and end regions. No regions above or below us will be considered by our children. They are - // effectively clamped to our region range. - computeRegionRangeForBlock(flowThread); - - setLogicalHeight(oldHeight); - setLogicalTop(oldTop); - - return shapeInfoRequiresRelayout(this); -} - -void RenderBlock::computeShapeSize() -{ - ShapeInsideInfo* shapeInsideInfo = this->shapeInsideInfo(); - if (!shapeInsideInfo) - return; - - if (isRenderNamedFlowFragment()) { - ShapeInsideInfo* parentShapeInsideInfo = toRenderBlock(parent())->shapeInsideInfo(); - ASSERT(parentShapeInsideInfo); - shapeInsideInfo->setShapeSize(parentShapeInsideInfo->shapeSize().width(), parentShapeInsideInfo->shapeSize().height()); - } else { - bool percentageLogicalHeightResolvable = percentageLogicalHeightIsResolvableFromBlock(this, false); - shapeInsideInfo->setShapeSize(logicalWidth(), percentageLogicalHeightResolvable ? logicalHeight() : LayoutUnit()); + LayoutRect screenArea; + if (!objectBounds.isEmpty()) { + screenArea = viewBounds; + screenArea.intersect(objectBounds); } -} -void RenderBlock::updateRegionsAndShapesAfterChildLayout(RenderFlowThread* flowThread, bool heightChanged) -{ - // A previous sibling has changed dimension, so we need to relayout the shape with the content - ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo(); - if (heightChanged && shapeInsideInfo) - shapeInsideInfo->dirtyShapeSize(); + for (Vector<ImageResource*>::iterator it = images.begin(), end = images.end(); it != end; ++it) + ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->notifyImageResourceVisibility(*it, status, screenArea); - computeRegionRangeForBlock(flowThread); + return true; } void RenderBlock::computeRegionRangeForBlock(RenderFlowThread* flowThread) @@ -1499,37 +1402,7 @@ bool RenderBlock::updateLogicalWidthAndColumnWidth() return oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth() || hasBorderOrPaddingLogicalWidthChanged; } -void RenderBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight) -{ - ColumnInfo* colInfo = columnInfo(); - if (hasColumns()) { - if (!pageLogicalHeight) { - // We need to go ahead and set our explicit page height if one exists, so that we can - // avoid doing two layout passes. - updateLogicalHeight(); - LayoutUnit columnHeight = contentLogicalHeight(); - if (columnHeight > 0) { - pageLogicalHeight = columnHeight; - hasSpecifiedPageLogicalHeight = true; - } - setLogicalHeight(0); - } - if (colInfo->columnHeight() != pageLogicalHeight && everHadLayout()) { - colInfo->setColumnHeight(pageLogicalHeight); - pageLogicalHeightChanged = true; - } - - if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight) - colInfo->clearForcedBreaks(); - - colInfo->setPaginationUnit(paginationUnit()); - } else if (isRenderFlowThread()) { - pageLogicalHeight = 1; // This is just a hack to always make sure we have a page logical height. - pageLogicalHeightChanged = toRenderFlowThread(this)->pageLogicalSizeChanged(); - } -} - -void RenderBlock::layoutBlock(bool, LayoutUnit) +void RenderBlock::layoutBlock(bool) { ASSERT_NOT_REACHED(); clearNeedsLayout(); @@ -1577,14 +1450,9 @@ void RenderBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool) m_overflow->setLayoutClientAfterEdge(oldClientAfterEdge); } - // Add visual overflow from box-shadow and border-image-outset. addVisualEffectOverflow(); - // Add visual overflow from theme. addVisualOverflowFromTheme(); - - if (isRenderNamedFlowThread()) - toRenderNamedFlowThread(this)->computeOversetStateForRegions(oldClientAfterEdge); } void RenderBlock::addOverflowFromBlockChildren() @@ -1622,79 +1490,10 @@ void RenderBlock::addVisualOverflowFromTheme() addVisualOverflow(inflatedRect); } -bool RenderBlock::expandsToEncloseOverhangingFloats() const +bool RenderBlock::createsBlockFormattingContext() const { - return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBoxIncludingDeprecated()) - || hasColumns() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot() || isRoot(); -} - -LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart, RenderRegion* region) -{ - LayoutUnit startPosition = startOffsetForContent(region); - - // Add in our start margin. - LayoutUnit oldPosition = startPosition + childMarginStart; - LayoutUnit newPosition = oldPosition; - - LayoutUnit blockOffset = logicalTopForChild(child); - if (region) - blockOffset = max(blockOffset, blockOffset + (region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage())); - - LayoutUnit startOff = startOffsetForLineInRegion(blockOffset, false, region, logicalHeightForChild(child)); - - if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) { - 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) - newPosition = startOff + childMarginStart; - - return newPosition - oldPosition; -} - -void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child, ApplyLayoutDeltaMode applyDelta) -{ - LayoutUnit startPosition = borderStart() + paddingStart(); - if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) - startPosition -= verticalScrollbarWidth(); - LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth(); - - // Add in our start margin. - LayoutUnit childMarginStart = marginStartForChild(child); - LayoutUnit newPosition = startPosition + childMarginStart; - - // 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() && !flowThreadContainingBlock()) - newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child)); - - setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta); -} - -void RenderBlock::setLogicalLeftForChild(RenderBox* child, LayoutUnit logicalLeft, ApplyLayoutDeltaMode applyDelta) -{ - if (isHorizontalWritingMode()) { - if (applyDelta == ApplyLayoutDelta) - view()->addLayoutDelta(LayoutSize(child->x() - logicalLeft, 0)); - child->setX(logicalLeft); - } else { - if (applyDelta == ApplyLayoutDelta) - view()->addLayoutDelta(LayoutSize(0, child->y() - logicalLeft)); - child->setY(logicalLeft); - } -} - -void RenderBlock::setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop, ApplyLayoutDeltaMode applyDelta) -{ - if (isHorizontalWritingMode()) { - if (applyDelta == ApplyLayoutDelta) - view()->addLayoutDelta(LayoutSize(0, child->y() - logicalTop)); - child->setY(logicalTop); - } else { - if (applyDelta == ApplyLayoutDelta) - view()->addLayoutDelta(LayoutSize(child->x() - logicalTop, 0)); - child->setX(logicalTop); - } + return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || isFlexItemIncludingDeprecated() + || style()->specifiesColumns() || isRenderFlowThread() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot() || isDocumentElement() || style()->columnSpan(); } void RenderBlock::updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, RenderBox* child) @@ -1718,8 +1517,8 @@ void RenderBlock::simplifiedNormalFlowLayout() if (!o->isOutOfFlowPositioned() && (o->isReplaced() || o->isFloating())) { o->layoutIfNeeded(); if (toRenderBox(o)->inlineBoxWrapper()) { - RootInlineBox* box = toRenderBox(o)->inlineBoxWrapper()->root(); - lineBoxes.add(box); + RootInlineBox& box = toRenderBox(o)->inlineBoxWrapper()->root(); + lineBoxes.add(&box); } } else if (o->isText() || (o->isRenderInline() && !walker.atEndOfInline())) { o->clearNeedsLayout(); @@ -1742,45 +1541,49 @@ void RenderBlock::simplifiedNormalFlowLayout() bool RenderBlock::simplifiedLayout() { - if ((!posChildNeedsLayout() && !needsSimplifiedNormalFlowLayout()) || normalChildNeedsLayout() || selfNeedsLayout()) + // Check if we need to do a full layout. + if (normalChildNeedsLayout() || selfNeedsLayout()) return false; - LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode()); - - if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly()) + // Check that we actually need to do a simplified layout. + if (!posChildNeedsLayout() && !(needsSimplifiedNormalFlowLayout() || needsPositionedMovementLayout())) return false; - // Lay out positioned descendants or objects that just need to recompute overflow. - if (needsSimplifiedNormalFlowLayout()) - simplifiedNormalFlowLayout(); - - // Make sure a forced break is applied after the content if we are a flow thread in a simplified layout. - // This ensures the size information is correctly computed for the last auto-height region receiving content. - if (isRenderFlowThread()) - toRenderFlowThread(this)->applyBreakAfterContent(clientLogicalBottom()); - - // Lay out our positioned objects if our positioned child bit is set. - // Also, if an absolute position element inside a relative positioned container moves, and the absolute element has a fixed position - // child, neither the fixed element nor its container learn of the movement since posChildNeedsLayout() is only marked as far as the - // relative positioned container. So if we can have fixed pos objects in our positioned objects list check if any of them - // are statically positioned and thus need to move with their absolute ancestors. - bool canContainFixedPosObjects = canContainFixedPositionObjects(); - if (posChildNeedsLayout() || canContainFixedPosObjects) - layoutPositionedObjects(false, !posChildNeedsLayout() && canContainFixedPosObjects); - - // Recompute our overflow information. - // FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only - // updating our overflow if we either used to have overflow or if the new temporary object has overflow. - // For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and - // lowestPosition on every relayout so it's not a regression. - // computeOverflow expects the bottom edge before we clamp our height. Since this information isn't available during - // simplifiedLayout, we cache the value in m_overflow. - LayoutUnit oldClientAfterEdge = hasRenderOverflow() ? m_overflow->layoutClientAfterEdge() : clientLogicalBottom(); - computeOverflow(oldClientAfterEdge, true); - statePusher.pop(); + { + // LayoutState needs this deliberate scope to pop before repaint + LayoutState state(*this, locationOffset()); + + if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly()) + return false; + + FastTextAutosizer::LayoutScope fastTextAutosizerLayoutScope(this); - updateLayerTransform(); + // Lay out positioned descendants or objects that just need to recompute overflow. + if (needsSimplifiedNormalFlowLayout()) + simplifiedNormalFlowLayout(); + + // Lay out our positioned objects if our positioned child bit is set. + // Also, if an absolute position element inside a relative positioned container moves, and the absolute element has a fixed position + // child, neither the fixed element nor its container learn of the movement since posChildNeedsLayout() is only marked as far as the + // relative positioned container. So if we can have fixed pos objects in our positioned objects list check if any of them + // are statically positioned and thus need to move with their absolute ancestors. + bool canContainFixedPosObjects = canContainFixedPositionObjects(); + if (posChildNeedsLayout() || needsPositionedMovementLayout() || canContainFixedPosObjects) + layoutPositionedObjects(false, needsPositionedMovementLayout() ? ForcedLayoutAfterContainingBlockMoved : (!posChildNeedsLayout() && canContainFixedPosObjects ? LayoutOnlyFixedPositionedObjects : DefaultLayout)); + + // Recompute our overflow information. + // FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only + // updating our overflow if we either used to have overflow or if the new temporary object has overflow. + // For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and + // lowestPosition on every relayout so it's not a regression. + // computeOverflow expects the bottom edge before we clamp our height. Since this information isn't available during + // simplifiedLayout, we cache the value in m_overflow. + LayoutUnit oldClientAfterEdge = hasRenderOverflow() ? m_overflow->layoutClientAfterEdge() : clientLogicalBottom(); + computeOverflow(oldClientAfterEdge, true); + } + + updateLayerTransformAfterLayout(); updateScrollInfoAfterLayout(); @@ -1806,9 +1609,10 @@ void RenderBlock::markFixedPositionObjectForLayoutIfNeeded(RenderObject* child, RenderBox* box = toRenderBox(child); if (hasStaticInlinePosition) { - LayoutUnit oldLeft = box->logicalLeft(); - box->updateLogicalWidth(); - if (box->logicalLeft() != oldLeft) + LogicalExtentComputedValues computedValues; + box->computeLogicalWidth(computedValues); + LayoutUnit newLeft = computedValues.m_position; + if (newLeft != box->logicalLeft()) layoutScope.setChildNeedsLayout(child); } else if (hasStaticBlockPosition) { LayoutUnit oldTop = box->logicalTop(); @@ -1833,7 +1637,7 @@ LayoutUnit RenderBlock::marginIntrinsicLogicalWidthForChild(RenderBox* child) co return margin; } -void RenderBlock::layoutPositionedObjects(bool relayoutChildren, bool fixedPositionObjectsOnly) +void RenderBlock::layoutPositionedObjects(bool relayoutChildren, PositionedLayoutBehavior info) { TrackedRendererListHashSet* positionedDescendants = positionedObjects(); if (!positionedDescendants) @@ -1847,12 +1651,15 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren, bool fixedPosit for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) { r = *it; - SubtreeLayoutScope layoutScope(r); + // FIXME: this should only be set from clearNeedsLayout crbug.com/361250 + r->setLayoutDidGetCalled(true); + + SubtreeLayoutScope layoutScope(*r); // A fixed position element with an absolute positioned ancestor has no way of knowing if the latter has changed position. So // if this is a fixed position element, mark it for layout if it has an abspos ancestor and needs to move with that ancestor, i.e. // it has static position. markFixedPositionObjectForLayoutIfNeeded(r, layoutScope); - if (fixedPositionObjectsOnly) { + if (info == LayoutOnlyFixedPositionedObjects) { r->layoutIfNeeded(); continue; } @@ -1871,11 +1678,6 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren, bool fixedPosit if (!r->needsLayout()) r->markForPaginationRelayoutIfNeeded(layoutScope); - // We don't have to do a full layout. We just have to update our position. Try that first. If we have shrink-to-fit width - // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout. - if (r->needsPositionedMovementLayoutOnly() && r->tryLayoutDoingPositionedMovementOnly()) - r->clearNeedsLayout(); - // If we are paginated or in a line grid, go ahead and compute a vertical position for our object now. // If it's wrong we'll lay out again. LayoutUnit oldLogicalTop = 0; @@ -1888,6 +1690,11 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren, bool fixedPosit oldLogicalTop = logicalTopForChild(r); } + // FIXME: We should be able to do a r->setNeedsPositionedMovementLayout() here instead of a full layout. Need + // to investigate why it does not trigger the correct invalidations in that case. crbug.com/350756 + if (info == ForcedLayoutAfterContainingBlockMoved) + r->setNeedsLayoutAndFullPaintInvalidation(); + r->layoutIfNeeded(); // Lay out again if our estimate was wrong. @@ -1896,7 +1703,7 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren, bool fixedPosit } 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. + view()->layoutState()->setColumnInfo(columnInfo()); // FIXME: Kind of gross. We just put this back into the layout state so that pop() will work. } void RenderBlock::markPositionedObjectsForLayout() @@ -1918,7 +1725,7 @@ void RenderBlock::markForPaginationRelayoutIfNeeded(SubtreeLayoutScope& layoutSc if (needsLayout()) return; - if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(this, logicalTop()) != pageLogicalOffset())) + if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(*this, logicalTop()) != pageLogicalOffset())) layoutScope.setChildNeedsLayout(this); } @@ -1930,13 +1737,13 @@ void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) PaintPhase phase = paintInfo.phase; + LayoutRect overflowBox; // Check if we need to do anything at all. - // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView + // FIXME: Could eliminate the isDocumentElement() check if we fix background painting so that the RenderView // paints the root's background. - if (!isRoot()) { - LayoutRect overflowBox = overflowRectForPaintRejection(); + if (!isDocumentElement()) { + overflowBox = overflowRectForPaintRejection(); flipForWritingMode(overflowBox); - overflowBox.inflate(maximalOutlineSize(paintInfo.phase)); overflowBox.moveBy(adjustedPaintOffset); if (!overflowBox.intersects(paintInfo.rect)) return; @@ -1949,7 +1756,16 @@ void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) contentsClipBehavior = SkipContentsClipIfPossible; bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset, contentsClipBehavior); - paintObject(paintInfo, adjustedPaintOffset); + { + GraphicsContextCullSaver cullSaver(*paintInfo.context); + // Cull if we have more than one child and we didn't already clip. + bool shouldCull = document().settings()->containerCullingEnabled() && !pushedClip && !isDocumentElement() + && firstChild() && lastChild() && firstChild() != lastChild(); + if (shouldCull) + cullSaver.cull(overflowBox); + + paintObject(paintInfo, adjustedPaintOffset); + } if (pushedClip) popContentsClip(paintInfo, phase, adjustedPaintOffset); @@ -1980,7 +1796,7 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& pain bool antialias = shouldAntialiasLines(paintInfo.context); if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) { - bool leftToRight = style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed(); + bool leftToRight = style()->isLeftToRightDirection(); LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : contentLogicalWidth(); LayoutUnit ruleAdd = logicalLeftOffsetForContent(); LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : contentLogicalWidth(); @@ -2012,13 +1828,13 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& pain ruleLogicalLeft = currLogicalLeftOffset; } } else { - bool topToBottom = !style()->isFlippedBlocksWritingMode() ^ colInfo->progressionIsReversed(); + bool topToBottom = !style()->isFlippedBlocksWritingMode(); LayoutUnit ruleLeft = isHorizontalWritingMode() ? borderLeft() + paddingLeft() - : colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter()); + : colGap / 2 - colGap - ruleThickness / 2 + borderBefore() + paddingBefore(); LayoutUnit ruleWidth = isHorizontalWritingMode() ? contentWidth() : ruleThickness; LayoutUnit ruleTop = isHorizontalWritingMode() - ? colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter()) + ? colGap / 2 - colGap - ruleThickness / 2 + borderBefore() + paddingBefore() : borderStart() + paddingStart(); LayoutUnit ruleHeight = isHorizontalWritingMode() ? ruleThickness : contentHeight(); LayoutRect ruleRect(ruleLeft, ruleTop, ruleWidth, ruleHeight); @@ -2072,7 +1888,7 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& p } colRect.moveBy(paintOffset); PaintInfo info(paintInfo); - info.rect.intersect(pixelSnappedIntRect(colRect)); + info.rect.intersect(enclosingIntRect(colRect)); if (!info.rect.isEmpty()) { GraphicsContextStateSaver stateSaver(*context); @@ -2088,7 +1904,7 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& p // like overflow:hidden. // FIXME: Content and column rules that extend outside column boxes at the edges of the multi-column element // are clipped according to the 'overflow' property. - context->clip(pixelSnappedIntRect(clipRect)); + context->clip(enclosingIntRect(clipRect)); // Adjust our x and y when painting. LayoutPoint adjustedPaintOffset = paintOffset + offset; @@ -2173,31 +1989,42 @@ void RenderBlock::paintAsInlineBlock(RenderObject* renderer, PaintInfo& paintInf } } -bool RenderBlock::hasCaret(CaretType type) const +static inline bool caretBrowsingEnabled(const Frame* frame) { - // Paint the caret if the FrameSelection says so or if caret browsing is enabled - bool caretBrowsing = frame()->settings() && frame()->settings()->caretBrowsingEnabled(); - RenderObject* caretPainter; - bool isContentEditable; - if (type == CursorCaret) { - caretPainter = frame()->selection().caretRenderer(); - isContentEditable = frame()->selection().rendererIsEditable(); - } else { - caretPainter = frame()->page()->dragCaretController().caretRenderer(); - isContentEditable = frame()->page()->dragCaretController().isContentEditable(); - } - return caretPainter == this && (isContentEditable || caretBrowsing); + Settings* settings = frame->settings(); + return settings && settings->caretBrowsingEnabled(); } -void RenderBlock::paintCaret(PaintInfo& paintInfo, const LayoutPoint& paintOffset, CaretType type) +static inline bool hasCursorCaret(const FrameSelection& selection, const RenderBlock* block, bool caretBrowsing) { - if (!hasCaret(type)) - return; + return selection.caretRenderer() == block && (selection.rendererIsEditable() || caretBrowsing); +} - if (type == CursorCaret) - frame()->selection().paintCaret(paintInfo.context, paintOffset, paintInfo.rect); - else - frame()->page()->dragCaretController().paintDragCaret(frame(), paintInfo.context, paintOffset, paintInfo.rect); +static inline bool hasDragCaret(const DragCaretController& dragCaretController, const RenderBlock* block, bool caretBrowsing) +{ + return dragCaretController.caretRenderer() == block && (dragCaretController.isContentEditable() || caretBrowsing); +} + +bool RenderBlock::hasCaret() const +{ + bool caretBrowsing = caretBrowsingEnabled(frame()); + return hasCursorCaret(frame()->selection(), this, caretBrowsing) + || hasDragCaret(frame()->page()->dragCaretController(), this, caretBrowsing); +} + +void RenderBlock::paintCarets(PaintInfo& paintInfo, const LayoutPoint& paintOffset) +{ + bool caretBrowsing = caretBrowsingEnabled(frame()); + + FrameSelection& selection = frame()->selection(); + if (hasCursorCaret(selection, this, caretBrowsing)) { + selection.paintCaret(paintInfo.context, paintOffset, paintInfo.rect); + } + + DragCaretController& dragCaretController = frame()->page()->dragCaretController(); + if (hasDragCaret(dragCaretController, this, caretBrowsing)) { + dragCaretController.paintDragCaret(frame(), paintInfo.context, paintOffset, paintInfo.rect); + } } void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset) @@ -2287,8 +2114,7 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffs // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground, // then paint the caret. if (paintPhase == PaintPhaseForeground) { - paintCaret(paintInfo, paintOffset, CursorCaret); - paintCaret(paintInfo, paintOffset, DragCaret); + paintCarets(paintInfo, paintOffset); } } @@ -2383,11 +2209,11 @@ bool RenderBlock::isSelectionRoot() const if (isTable()) return false; - if (isBody() || isRoot() || hasOverflowClip() + if (isBody() || isDocumentElement() || hasOverflowClip() || isPositioned() || isFloating() || isTableCell() || isInlineBlockOrInlineTable() || hasTransform() || hasReflection() || hasMask() || isWritingModeRoot() - || isRenderFlowThread()) + || isRenderFlowThread() || isFlexItemIncludingDeprecated()) return true; if (view() && view()->selectionStart()) { @@ -2430,17 +2256,16 @@ void RenderBlock::paintSelection(PaintInfo& paintInfo, const LayoutPoint& paintO LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, &paintInfo); if (!gapRectsBounds.isEmpty()) { - if (RenderLayer* layer = enclosingLayer()) { - gapRectsBounds.moveBy(-paintOffset); - if (!hasLayer()) { - LayoutRect localBounds(gapRectsBounds); - flipForWritingMode(localBounds); - gapRectsBounds = localToContainerQuad(FloatRect(localBounds), layer->renderer()).enclosingBoundingBox(); - if (layer->renderer()->hasOverflowClip()) - gapRectsBounds.move(layer->renderBox()->scrolledContentOffset()); - } - layer->addBlockSelectionGapsBounds(gapRectsBounds); + RenderLayer* layer = enclosingLayer(); + gapRectsBounds.moveBy(-paintOffset); + if (!hasLayer()) { + LayoutRect localBounds(gapRectsBounds); + flipForWritingMode(localBounds); + gapRectsBounds = localToContainerQuad(FloatRect(localBounds), layer->renderer()).enclosingBoundingBox(); + if (layer->renderer()->hasOverflowClip()) + gapRectsBounds.move(layer->renderBox()->scrolledContentOffset()); } + layer->addBlockSelectionGapsBounds(gapRectsBounds); } } } @@ -2490,7 +2315,7 @@ GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& r rootBlock->flipForWritingMode(flippedBlockRect); flippedBlockRect.moveBy(rootBlockPhysicalPosition); clipOutPositionedObjects(paintInfo, flippedBlockRect.location(), positionedObjects()); - if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects. + if (isBody() || isDocumentElement()) // The <body> must make sure to examine its containingBlock's positioned objects. for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock()) clipOutPositionedObjects(paintInfo, LayoutPoint(cb->x(), cb->y()), cb->positionedObjects()); // FIXME: Not right for flipped writing modes. clipOutFloatingObjects(rootBlock, paintInfo, rootBlockPhysicalPosition, offsetFromRootBlock); @@ -2650,38 +2475,18 @@ void RenderBlock::getSelectionGapInfo(SelectionState state, bool& leftGap, bool& LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position) { - LayoutUnit logicalLeft = logicalLeftOffsetForLine(position, false); - if (logicalLeft == logicalLeftOffsetForContent()) { - if (rootBlock != this) - // The border can potentially be further extended by our containingBlock(). - return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop()); - return logicalLeft; - } else { - RenderBlock* cb = this; - while (cb != rootBlock) { - logicalLeft += cb->logicalLeft(); - cb = cb->containingBlock(); - } - } - return logicalLeft; + // The border can potentially be further extended by our containingBlock(). + if (rootBlock != this) + return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop()); + return logicalLeftOffsetForContent(); } LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position) { - LayoutUnit logicalRight = logicalRightOffsetForLine(position, false); - if (logicalRight == logicalRightOffsetForContent()) { - if (rootBlock != this) - // The border can potentially be further extended by our containingBlock(). - return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop()); - return logicalRight; - } else { - RenderBlock* cb = this; - while (cb != rootBlock) { - logicalRight += cb->logicalLeft(); - cb = cb->containingBlock(); - } - } - return logicalRight; + // The border can potentially be further extended by our containingBlock(). + if (rootBlock != this) + return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop()); + return logicalRightOffsetForContent(); } RenderBlock* RenderBlock::blockBeforeWithinSelectionRoot(LayoutSize& offset) const @@ -2900,7 +2705,7 @@ void RenderBlock::removePercentHeightDescendantIfNeeded(RenderBox* descendant) void RenderBlock::clearPercentHeightDescendantsFrom(RenderBox* parent) { ASSERT(gPercentHeightContainerMap); - for (RenderObject* curr = parent->firstChild(); curr; curr = curr->nextInPreOrder(parent)) { + for (RenderObject* curr = parent->slowFirstChild(); curr; curr = curr->nextInPreOrder(parent)) { if (!curr->isBox()) continue; @@ -2915,107 +2720,9 @@ void RenderBlock::clearPercentHeightDescendantsFrom(RenderBox* parent) LayoutUnit RenderBlock::textIndentOffset() const { LayoutUnit cw = 0; - RenderView* renderView = 0; if (style()->textIndent().isPercent()) cw = containingBlock()->availableLogicalWidth(); - else if (style()->textIndent().isViewportPercentage()) - renderView = view(); - return minimumValueForLength(style()->textIndent(), cw, renderView); -} - -LayoutUnit RenderBlock::logicalLeftOffsetForContent(RenderRegion* region) const -{ - LayoutUnit logicalLeftOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop(); - if (!region) - return logicalLeftOffset; - LayoutRect boxRect = borderBoxRectInRegion(region); - return logicalLeftOffset + (isHorizontalWritingMode() ? boxRect.x() : boxRect.y()); -} - -LayoutUnit RenderBlock::logicalRightOffsetForContent(RenderRegion* region) const -{ - LayoutUnit logicalRightOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop(); - logicalRightOffset += availableLogicalWidth(); - if (!region) - return logicalRightOffset; - LayoutRect boxRect = borderBoxRectInRegion(region); - return logicalRightOffset - (logicalWidth() - (isHorizontalWritingMode() ? boxRect.maxX() : boxRect.maxY())); -} - -LayoutUnit RenderBlock::adjustLogicalLeftOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const -{ - LayoutUnit left = offsetFromFloats; - - if (applyTextIndent && style()->isLeftToRightDirection()) - left += textIndentOffset(); - - if (style()->lineAlign() == LineAlignNone) - return left; - - // Push in our left offset so that it is aligned with the character grid. - LayoutState* layoutState = view()->layoutState(); - if (!layoutState) - return left; - - RenderBlock* lineGrid = layoutState->lineGrid(); - if (!lineGrid || lineGrid->style()->writingMode() != style()->writingMode()) - return left; - - // FIXME: Should letter-spacing apply? This is complicated since it doesn't apply at the edge? - float maxCharWidth = lineGrid->style()->font().primaryFont()->maxCharWidth(); - if (!maxCharWidth) - return left; - - LayoutUnit lineGridOffset = lineGrid->isHorizontalWritingMode() ? layoutState->lineGridOffset().width(): layoutState->lineGridOffset().height(); - LayoutUnit layoutOffset = lineGrid->isHorizontalWritingMode() ? layoutState->layoutOffset().width() : layoutState->layoutOffset().height(); - - // Push in to the nearest character width. - // FIXME: This is wrong for RTL (https://bugs.webkit.org/show_bug.cgi?id=79945). - // FIXME: This doesn't work with columns or regions (https://bugs.webkit.org/show_bug.cgi?id=79942). - // FIXME: This doesn't work when the inline position of the object isn't set ahead of time. - // FIXME: Dynamic changes to the font or to the inline position need to result in a deep relayout. - // (https://bugs.webkit.org/show_bug.cgi?id=79944) - float remainder = fmodf(maxCharWidth - fmodf(left + layoutOffset - lineGridOffset, maxCharWidth), maxCharWidth); - left += remainder; - return left; -} - -LayoutUnit RenderBlock::adjustLogicalRightOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const -{ - LayoutUnit right = offsetFromFloats; - - if (applyTextIndent && !style()->isLeftToRightDirection()) - right -= textIndentOffset(); - - if (style()->lineAlign() == LineAlignNone) - return right; - - // Push in our right offset so that it is aligned with the character grid. - LayoutState* layoutState = view()->layoutState(); - if (!layoutState) - return right; - - RenderBlock* lineGrid = layoutState->lineGrid(); - if (!lineGrid || lineGrid->style()->writingMode() != style()->writingMode()) - return right; - - // FIXME: Should letter-spacing apply? This is complicated since it doesn't apply at the edge? - float maxCharWidth = lineGrid->style()->font().primaryFont()->maxCharWidth(); - if (!maxCharWidth) - return right; - - LayoutUnit lineGridOffset = lineGrid->isHorizontalWritingMode() ? layoutState->lineGridOffset().width(): layoutState->lineGridOffset().height(); - LayoutUnit layoutOffset = lineGrid->isHorizontalWritingMode() ? layoutState->layoutOffset().width() : layoutState->layoutOffset().height(); - - // Push in to the nearest character width. - // FIXME: This is wrong for RTL (https://bugs.webkit.org/show_bug.cgi?id=79945). - // FIXME: This doesn't work with columns or regions (https://bugs.webkit.org/show_bug.cgi?id=79942). - // FIXME: This doesn't work when the inline position of the object isn't set ahead of time. - // FIXME: Dynamic changes to the font or to the inline position need to result in a deep relayout. - // (https://bugs.webkit.org/show_bug.cgi?id=79944) - float remainder = fmodf(fmodf(right + layoutOffset - lineGridOffset, maxCharWidth), maxCharWidth); - right -= LayoutUnit::fromFloatCeil(remainder); - return right; + return minimumValueForLength(style()->textIndent(), cw); } void RenderBlock::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest) @@ -3042,22 +2749,6 @@ bool RenderBlock::avoidsFloats() const return RenderBox::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth(); } -void RenderBlock::markShapeInsideDescendantsForLayout() -{ - if (!everHadLayout()) - return; - if (childrenInline()) { - setNeedsLayout(); - return; - } - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (!child->isRenderBlock()) - continue; - RenderBlock* childBlock = toRenderBlock(child); - childBlock->markShapeInsideDescendantsForLayout(); - } -} - bool RenderBlock::isPointInOverflowControl(HitTestResult& result, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset) { if (!scrollsOverflow()) @@ -3081,24 +2772,53 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu if (!isRenderView()) { // Check if we need to do anything at all. - LayoutRect overflowBox = visualOverflowRect(); + // If we have clipping, then we can't have any spillout. + LayoutRect overflowBox = hasOverflowClip() ? borderBoxRect() : visualOverflowRect(); flipForWritingMode(overflowBox); overflowBox.moveBy(adjustedLocation); if (!locationInContainer.intersects(overflowBox)) return false; } - if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && isPointInOverflowControl(result, locationInContainer.point(), adjustedLocation)) { + if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) + && visibleToHitTestRequest(request) + && isPointInOverflowControl(result, locationInContainer.point(), adjustedLocation)) { updateHitTestResult(result, locationInContainer.point() - localOffset); // FIXME: isPointInOverflowControl() doesn't handle rect-based tests yet. if (!result.addNodeToRectBasedTestResult(nodeForHitTest(), request, locationInContainer)) return true; } + if (style()->clipPath()) { + switch (style()->clipPath()->type()) { + case ClipPathOperation::SHAPE: { + ShapeClipPathOperation* clipPath = toShapeClipPathOperation(style()->clipPath()); + // FIXME: handle marginBox etc. + if (!clipPath->path(borderBoxRect()).contains(locationInContainer.point() - localOffset, clipPath->windRule())) + return false; + break; + } + case ClipPathOperation::REFERENCE: + // FIXME: handle REFERENCE + break; + } + } + // If we have clipping, then we can't have any spillout. bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer(); bool useClip = (hasControlClip() || useOverflowClip); - bool checkChildren = !useClip || (hasControlClip() ? locationInContainer.intersects(controlClipRect(adjustedLocation)) : locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region(), IncludeOverlayScrollbarSize))); + bool checkChildren = !useClip; + if (!checkChildren) { + if (hasControlClip()) { + checkChildren = locationInContainer.intersects(controlClipRect(adjustedLocation)); + } else { + LayoutRect clipRect = overflowClipRect(adjustedLocation, IncludeOverlayScrollbarSize); + if (style()->hasBorderRadius()) + checkChildren = locationInContainer.intersects(style()->getRoundedBorderFor(clipRect)); + else + checkChildren = locationInContainer.intersects(clipRect); + } + } if (checkChildren) { // Hit test descendants first. LayoutSize scrolledOffset(localOffset); @@ -3120,10 +2840,10 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu } // Check if the point is outside radii. - if (!isRenderView() && style()->hasBorderRadius()) { + if (style()->hasBorderRadius()) { LayoutRect borderRect = borderBoxRect(); borderRect.moveBy(adjustedLocation); - RoundedRect border = style()->getRoundedBorderFor(borderRect, view()); + RoundedRect border = style()->getRoundedBorderFor(borderRect); if (!locationInContainer.intersects(border)) return false; } @@ -3239,9 +2959,6 @@ void RenderBlock::adjustForColumnRect(LayoutSize& offset, const LayoutPoint& loc bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { - if (isRenderRegion()) - return toRenderRegion(this)->hitTestFlowThreadContents(request, result, locationInContainer, accumulatedOffset, hitTestAction); - if (childrenInline() && !isTable()) { // We have to hit-test our line boxes. if (m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction)) @@ -3266,14 +2983,14 @@ Position RenderBlock::positionForBox(InlineBox *box, bool start) const if (!box) return Position(); - if (!box->renderer()->nonPseudoNode()) + if (!box->renderer().nonPseudoNode()) return createLegacyEditingPosition(nonPseudoNode(), start ? caretMinOffset() : caretMaxOffset()); if (!box->isInlineTextBox()) - return createLegacyEditingPosition(box->renderer()->nonPseudoNode(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset()); + return createLegacyEditingPosition(box->renderer().nonPseudoNode(), start ? box->renderer().caretMinOffset() : box->renderer().caretMaxOffset()); InlineTextBox* textBox = toInlineTextBox(box); - return createLegacyEditingPosition(box->renderer()->nonPseudoNode(), start ? textBox->start() : textBox->start() + textBox->len()); + return createLegacyEditingPosition(box->renderer().nonPseudoNode(), start ? textBox->start() : textBox->start() + textBox->len()); } static inline bool isEditingBoundary(RenderObject* ancestor, RenderObject* child) @@ -3385,12 +3102,12 @@ PositionWithAffinity RenderBlock::positionForPointWithInlineChildren(const Layou } // pass the box a top position that is inside it - LayoutPoint point(pointInLogicalContents.x(), closestBox->root()->blockDirectionPointInLine()); + LayoutPoint point(pointInLogicalContents.x(), closestBox->root().blockDirectionPointInLine()); if (!isHorizontalWritingMode()) point = point.transposedPoint(); - if (closestBox->renderer()->isReplaced()) - return positionForPointRespectingEditingBoundaries(this, toRenderBox(closestBox->renderer()), point); - return closestBox->renderer()->positionForPoint(point); + if (closestBox->renderer().isReplaced()) + return positionForPointRespectingEditingBoundaries(this, &toRenderBox(closestBox->renderer()), point); + return closestBox->renderer().positionForPoint(point); } if (lastRootBoxWithChildren) { @@ -3505,7 +3222,7 @@ void RenderBlock::calcColumnWidth() LayoutUnit desiredColumnWidth = contentLogicalWidth(); // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination. - if (document().paginated() || (style()->hasAutoColumnCount() && style()->hasAutoColumnWidth()) || !style()->hasInlineColumnAxis()) { + if (document().paginated() || !style()->specifiesColumns()) { setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth); return; } @@ -3530,12 +3247,12 @@ void RenderBlock::calcColumnWidth() bool RenderBlock::requiresColumns(int desiredColumnCount) const { - // If overflow-y is set to paged-x or paged-y on the body or html element, we'll handle the paginating - // in the RenderView instead. - bool isPaginated = (style()->overflowY() == OPAGEDX || style()->overflowY() == OPAGEDY) && !(isRoot() || isBody()); + // Paged overflow is treated as multicol here, unless this element was the one that got its + // overflow propagated to the viewport. + bool isPaginated = style()->isOverflowPaged() && node() != document().viewportDefiningElement(); return firstChild() - && (desiredColumnCount != 1 || !style()->hasAutoColumnWidth() || !style()->hasInlineColumnAxis() || isPaginated) + && (desiredColumnCount != 1 || !style()->hasAutoColumnWidth() || isPaginated) && !firstChild()->isAnonymousColumnsBlock() && !firstChild()->isAnonymousColumnSpanBlock(); } @@ -3559,37 +3276,15 @@ void RenderBlock::setDesiredColumnCountAndWidth(int count, LayoutUnit width) gColumnInfoMap->add(this, adoptPtr(info)); setHasColumns(true); } - info->setDesiredColumnCount(count); info->setDesiredColumnWidth(width); - info->setProgressionAxis(style()->hasInlineColumnAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis); - info->setProgressionIsReversed(style()->columnProgression() == ReverseColumnProgression); - } -} - -void RenderBlock::updateColumnInfoFromStyle(RenderStyle* style) -{ - if (!hasColumns()) - return; - - ColumnInfo* info = gColumnInfoMap->get(this); - - bool needsLayout = false; - ColumnInfo::Axis oldAxis = info->progressionAxis(); - ColumnInfo::Axis newAxis = style->hasInlineColumnAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis; - if (oldAxis != newAxis) { - info->setProgressionAxis(newAxis); - needsLayout = true; - } - - bool oldProgressionIsReversed = info->progressionIsReversed(); - bool newProgressionIsReversed = style->columnProgression() == ReverseColumnProgression; - if (oldProgressionIsReversed != newProgressionIsReversed) { - info->setProgressionIsReversed(newProgressionIsReversed); - needsLayout = true; + if (style()->isOverflowPaged()) { + info->setDesiredColumnCount(1); + info->setProgressionAxis(style()->hasInlinePaginationAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis); + } else { + info->setDesiredColumnCount(count); + info->setProgressionAxis(ColumnInfo::InlineAxis); + } } - - if (needsLayout) - setNeedsLayoutAndPrefWidthsRecalc(); } LayoutUnit RenderBlock::desiredColumnWidth() const @@ -3624,15 +3319,12 @@ LayoutRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const LayoutUnit colLogicalLeft = logicalLeftOffsetForContent(); LayoutUnit colGap = columnGap(); if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) { - if (style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed()) + if (style()->isLeftToRightDirection()) colLogicalLeft += index * (colLogicalWidth + colGap); else colLogicalLeft += contentLogicalWidth() - colLogicalWidth - index * (colLogicalWidth + colGap); } else { - if (!colInfo->progressionIsReversed()) - colLogicalTop += index * (colLogicalHeight + colGap); - else - colLogicalTop += contentLogicalHeight() - colLogicalHeight - index * (colLogicalHeight + colGap); + colLogicalTop += index * (colLogicalHeight + colGap); } if (isHorizontalWritingMode()) @@ -3640,17 +3332,6 @@ LayoutRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogicalWidth); } -bool RenderBlock::relayoutToAvoidWidows(LayoutStateMaintainer& statePusher) -{ - if (!shouldBreakAtLineToAvoidWidow()) - return false; - - statePusher.pop(); - setEverHadLayout(true); - layoutBlock(false); - return true; -} - void RenderBlock::adjustPointToColumnContents(LayoutPoint& point) const { // Just bail if we have no columns. @@ -3826,10 +3507,10 @@ void RenderBlock::adjustStartEdgeForWritingModeIncludingColumns(LayoutRect& rect rect.setX(expandedLogicalHeight - rect.maxX()); } -void RenderBlock::adjustForColumns(LayoutSize& offset, const LayoutPoint& point) const +LayoutSize RenderBlock::columnOffset(const LayoutPoint& point) const { if (!hasColumns()) - return; + return LayoutSize(); ColumnInfo* colInfo = columnInfo(); @@ -3850,30 +3531,29 @@ void RenderBlock::adjustForColumns(LayoutSize& offset, const LayoutPoint& point) if (isHorizontalWritingMode()) { if (point.y() >= sliceRect.y() && point.y() < sliceRect.maxY()) { if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) - offset.expand(columnRectAt(colInfo, i).x() - logicalLeft, -logicalOffset); - else - offset.expand(0, columnRectAt(colInfo, i).y() - logicalOffset - borderBefore() - paddingBefore()); - return; + return LayoutSize(columnRectAt(colInfo, i).x() - logicalLeft, -logicalOffset); + return LayoutSize(0, columnRectAt(colInfo, i).y() - logicalOffset - borderBefore() - paddingBefore()); } } else { if (point.x() >= sliceRect.x() && point.x() < sliceRect.maxX()) { if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) - offset.expand(-logicalOffset, columnRectAt(colInfo, i).y() - logicalLeft); - else - offset.expand(columnRectAt(colInfo, i).x() - logicalOffset - borderBefore() - paddingBefore(), 0); - return; + return LayoutSize(-logicalOffset, columnRectAt(colInfo, i).y() - logicalLeft); + return LayoutSize(columnRectAt(colInfo, i).x() - logicalOffset - borderBefore() - paddingBefore(), 0); } } } + + return LayoutSize(); } void RenderBlock::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const { if (childrenInline()) { // FIXME: Remove this const_cast. - const_cast<RenderBlock*>(this)->computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth); - } else + toRenderBlockFlow(const_cast<RenderBlock*>(this))->computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth); + } else { computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth); + } maxLogicalWidth = max(minLogicalWidth, maxLogicalWidth); @@ -3937,9 +3617,6 @@ void RenderBlock::computePreferredLogicalWidths() void RenderBlock::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const { - // FIXME: make this method virtual and move the code to RenderMultiColumnBlock once the old - // multicol code is gone. - if (!style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth()) { // The min/max intrinsic widths calculated really tell how much space elements need when // laid out inside the columns. In order to eventually end up with the desired column width, @@ -3962,429 +3639,6 @@ void RenderBlock::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalW } } -struct InlineMinMaxIterator { -/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to - inline min/max width calculations. Note the following about the way it walks: - (1) Positioned content is skipped (since it does not contribute to min/max width of a block) - (2) We do not drill into the children of floats or replaced elements, since you can't break - in the middle of such an element. - (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have - distinct borders/margin/padding that contribute to the min/max width. -*/ - RenderObject* parent; - RenderObject* current; - bool endOfInline; - - InlineMinMaxIterator(RenderObject* p, bool end = false) - :parent(p), current(p), endOfInline(end) {} - - RenderObject* next(); -}; - -RenderObject* InlineMinMaxIterator::next() -{ - RenderObject* result = 0; - bool oldEndOfInline = endOfInline; - endOfInline = false; - while (current || current == parent) { - if (!oldEndOfInline && - (current == parent || - (!current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned()))) - result = current->firstChild(); - if (!result) { - // We hit the end of our inline. (It was empty, e.g., <span></span>.) - if (!oldEndOfInline && current->isRenderInline()) { - result = current; - endOfInline = true; - break; - } - - while (current && current != parent) { - result = current->nextSibling(); - if (result) break; - current = current->parent(); - if (current && current != parent && current->isRenderInline()) { - result = current; - endOfInline = true; - break; - } - } - } - - if (!result) - break; - - if (!result->isOutOfFlowPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline())) - break; - - current = result; - result = 0; - } - - // Update our position. - current = result; - return current; -} - -static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit) -{ - if (cssUnit.type() != Auto) - return (cssUnit.isFixed() ? static_cast<LayoutUnit>(cssUnit.value()) : childValue); - return 0; -} - -static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline) -{ - RenderStyle* childStyle = child->style(); - if (endOfInline) - return getBPMWidth(child->marginEnd(), childStyle->marginEnd()) + - getBPMWidth(child->paddingEnd(), childStyle->paddingEnd()) + - child->borderEnd(); - return getBPMWidth(child->marginStart(), childStyle->marginStart()) + - getBPMWidth(child->paddingStart(), childStyle->paddingStart()) + - child->borderStart(); -} - -static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, - RenderObject* trailingSpaceChild) -{ - if (trailingSpaceChild && trailingSpaceChild->isText()) { - // Collapse away the trailing space at the end of a block. - RenderText* t = toRenderText(trailingSpaceChild); - const UChar space = ' '; - const Font& font = t->style()->font(); // FIXME: This ignores first-line. - float spaceWidth = font.width(RenderBlockFlow::constructTextRun(t, font, &space, 1, t->style())); - inlineMax -= spaceWidth + font.wordSpacing(); - if (inlineMin > inlineMax) - inlineMin = inlineMax; - } -} - -static inline void updatePreferredWidth(LayoutUnit& preferredWidth, float& result) -{ - LayoutUnit snappedResult = LayoutUnit::fromFloatCeil(result); - preferredWidth = max(snappedResult, preferredWidth); -} - -// When converting between floating point and LayoutUnits we risk losing precision -// with each conversion. When this occurs while accumulating our preferred widths, -// we can wind up with a line width that's larger than our maxPreferredWidth due to -// pure float accumulation. -static inline LayoutUnit adjustFloatForSubPixelLayout(float value) -{ - return LayoutUnit::fromFloatCeil(value); -} - - -void RenderBlock::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) -{ - float inlineMax = 0; - float inlineMin = 0; - - RenderStyle* styleToUse = style(); - RenderBlock* containingBlock = this->containingBlock(); - LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit(); - - // 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. - bool stripFrontSpaces = true; - RenderObject* trailingSpaceChild = 0; - - // Firefox and Opera will allow a table cell to grow to fit an image inside it under - // very specific cirucumstances (in order to match common WinIE renderings). - // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.) - bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse->logicalWidth().isIntrinsicOrAuto(); - - bool autoWrap, oldAutoWrap; - autoWrap = oldAutoWrap = styleToUse->autoWrap(); - - InlineMinMaxIterator childIterator(this); - - // Only gets added to the max preffered width once. - bool addedTextIndent = false; - // Signals the text indent was more negative than the min preferred width - bool hasRemainingNegativeTextIndent = false; - - LayoutUnit textIndent = minimumValueForLength(styleToUse->textIndent(), cw, view()); - RenderObject* prevFloat = 0; - bool isPrevChildInlineFlow = false; - bool shouldBreakLineAfterText = false; - while (RenderObject* child = childIterator.next()) { - autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() : - child->style()->autoWrap(); - - if (!child->isBR()) { - // Step One: determine whether or not we need to go ahead and - // terminate our current line. Each discrete chunk can become - // the new min-width, if it is the widest chunk seen so far, and - // it can also become the max-width. - - // Children fall into three categories: - // (1) An inline flow object. These objects always have a min/max of 0, - // and are included in the iteration solely so that their margins can - // be added in. - // - // (2) An inline non-text non-flow object, e.g., an inline replaced element. - // These objects can always be on a line by themselves, so in this situation - // we need to go ahead and break the current line, and then add in our own - // margins and min/max width on its own line, and then terminate the line. - // - // (3) A text object. Text runs can have breakable characters at the start, - // the middle or the end. They may also lose whitespace off the front if - // we're already ignoring whitespace. In order to compute accurate min-width - // information, we need three pieces of information. - // (a) the min-width of the first non-breakable run. Should be 0 if the text string - // starts with whitespace. - // (b) the min-width of the last non-breakable run. Should be 0 if the text string - // ends with whitespace. - // (c) the min/max width of the string (trimmed for whitespace). - // - // If the text string starts with whitespace, then we need to go ahead and - // terminate our current line (unless we're already in a whitespace stripping - // mode. - // - // If the text string has a breakable character in the middle, but didn't start - // with whitespace, then we add the width of the first non-breakable run and - // then end the current line. We then need to use the intermediate min/max width - // values (if any of them are larger than our current min/max). We then look at - // the width of the last non-breakable run and use that to start a new line - // (unless we end in whitespace). - RenderStyle* childStyle = child->style(); - float childMin = 0; - float childMax = 0; - - if (!child->isText()) { - // Case (1) and (2). Inline replaced and inline flow elements. - if (child->isRenderInline()) { - // Add in padding/border/margin from the appropriate side of - // the element. - float bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline); - childMin += bpm; - childMax += bpm; - - inlineMin += childMin; - inlineMax += childMax; - - child->clearPreferredLogicalWidthsDirty(); - } else { - // Inline replaced elts add in their margins to their min/max values. - LayoutUnit margins = 0; - Length startMargin = childStyle->marginStart(); - Length endMargin = childStyle->marginEnd(); - if (startMargin.isFixed()) - margins += adjustFloatForSubPixelLayout(startMargin.value()); - if (endMargin.isFixed()) - margins += adjustFloatForSubPixelLayout(endMargin.value()); - childMin += margins.ceilToFloat(); - childMax += margins.ceilToFloat(); - } - } - - if (!child->isRenderInline() && !child->isText()) { - // Case (2). Inline replaced elements and floats. - // Go ahead and terminate the current line as far as - // minwidth is concerned. - LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth; - if (child->isBox() && child->isHorizontalWritingMode() != isHorizontalWritingMode()) { - RenderBox* childBox = toRenderBox(child); - LogicalExtentComputedValues computedValues; - childBox->computeLogicalHeight(childBox->borderAndPaddingLogicalHeight(), 0, computedValues); - childMinPreferredLogicalWidth = childMaxPreferredLogicalWidth = computedValues.m_extent; - } else { - childMinPreferredLogicalWidth = child->minPreferredLogicalWidth(); - childMaxPreferredLogicalWidth = child->maxPreferredLogicalWidth(); - } - childMin += childMinPreferredLogicalWidth.ceilToFloat(); - childMax += childMaxPreferredLogicalWidth.ceilToFloat(); - - bool clearPreviousFloat; - if (child->isFloating()) { - clearPreviousFloat = (prevFloat - && ((prevFloat->style()->floating() == LeftFloat && (childStyle->clear() & CLEFT)) - || (prevFloat->style()->floating() == RightFloat && (childStyle->clear() & CRIGHT)))); - prevFloat = child; - } else - clearPreviousFloat = false; - - bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak; - if ((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) { - updatePreferredWidth(minLogicalWidth, inlineMin); - inlineMin = 0; - } - - // If we're supposed to clear the previous float, then terminate maxwidth as well. - if (clearPreviousFloat) { - updatePreferredWidth(maxLogicalWidth, inlineMax); - inlineMax = 0; - } - - // Add in text-indent. This is added in only once. - if (!addedTextIndent && !child->isFloating()) { - float ceiledTextIndent = textIndent.ceilToFloat(); - childMin += ceiledTextIndent; - childMax += ceiledTextIndent; - - if (childMin < 0) - textIndent = adjustFloatForSubPixelLayout(childMin); - else - addedTextIndent = true; - } - - // Add our width to the max. - inlineMax += max<float>(0, childMax); - - if (!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) { - if (child->isFloating()) - updatePreferredWidth(minLogicalWidth, childMin); - else - inlineMin += childMin; - } else { - // Now check our line. - updatePreferredWidth(minLogicalWidth, childMin); - - // Now start a new line. - inlineMin = 0; - } - - if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) { - updatePreferredWidth(minLogicalWidth, inlineMin); - inlineMin = 0; - } - - // We are no longer stripping whitespace at the start of - // a line. - if (!child->isFloating()) { - stripFrontSpaces = false; - trailingSpaceChild = 0; - } - } else if (child->isText()) { - // Case (3). Text. - RenderText* t = toRenderText(child); - - if (t->isWordBreak()) { - updatePreferredWidth(minLogicalWidth, inlineMin); - inlineMin = 0; - continue; - } - - if (t->style()->hasTextCombine() && t->isCombineText()) - toRenderCombineText(t)->combineText(); - - // Determine if we have a breakable character. Pass in - // whether or not we should ignore any spaces at the front - // of the string. If those are going to be stripped out, - // then they shouldn't be considered in the breakable char - // check. - bool hasBreakableChar, hasBreak; - float firstLineMinWidth, lastLineMinWidth; - bool hasBreakableStart, hasBreakableEnd; - float firstLineMaxWidth, lastLineMaxWidth; - t->trimmedPrefWidths(inlineMax, - firstLineMinWidth, hasBreakableStart, lastLineMinWidth, hasBreakableEnd, - hasBreakableChar, hasBreak, firstLineMaxWidth, lastLineMaxWidth, - childMin, childMax, stripFrontSpaces); - - // This text object will not be rendered, but it may still provide a breaking opportunity. - if (!hasBreak && childMax == 0) { - if (autoWrap && (hasBreakableStart || hasBreakableEnd)) { - updatePreferredWidth(minLogicalWidth, inlineMin); - inlineMin = 0; - } - continue; - } - - if (stripFrontSpaces) - trailingSpaceChild = child; - else - trailingSpaceChild = 0; - - // Add in text-indent. This is added in only once. - float ti = 0; - if (!addedTextIndent || hasRemainingNegativeTextIndent) { - ti = textIndent.ceilToFloat(); - childMin += ti; - firstLineMinWidth += ti; - - // It the text indent negative and larger than the child minimum, we re-use the remainder - // in future minimum calculations, but using the negative value again on the maximum - // will lead to under-counting the max pref width. - if (!addedTextIndent) { - childMax += ti; - firstLineMaxWidth += ti; - addedTextIndent = true; - } - - if (childMin < 0) { - textIndent = childMin; - hasRemainingNegativeTextIndent = true; - } - } - - // If we have no breakable characters at all, - // then this is the easy case. We add ourselves to the current - // min and max and continue. - if (!hasBreakableChar) { - inlineMin += childMin; - } else { - if (hasBreakableStart) { - updatePreferredWidth(minLogicalWidth, inlineMin); - } else { - inlineMin += firstLineMinWidth; - updatePreferredWidth(minLogicalWidth, inlineMin); - childMin -= ti; - } - - inlineMin = childMin; - - if (hasBreakableEnd) { - updatePreferredWidth(minLogicalWidth, inlineMin); - inlineMin = 0; - shouldBreakLineAfterText = false; - } else { - updatePreferredWidth(minLogicalWidth, inlineMin); - inlineMin = lastLineMinWidth; - shouldBreakLineAfterText = true; - } - } - - if (hasBreak) { - inlineMax += firstLineMaxWidth; - updatePreferredWidth(maxLogicalWidth, inlineMax); - updatePreferredWidth(maxLogicalWidth, childMax); - inlineMax = lastLineMaxWidth; - addedTextIndent = true; - } else { - inlineMax += max<float>(0, childMax); - } - } - - // Ignore spaces after a list marker. - if (child->isListMarker()) - stripFrontSpaces = true; - } else { - updatePreferredWidth(minLogicalWidth, inlineMin); - updatePreferredWidth(maxLogicalWidth, inlineMax); - inlineMin = inlineMax = 0; - stripFrontSpaces = true; - trailingSpaceChild = 0; - addedTextIndent = true; - } - - if (!child->isText() && child->isRenderInline()) - isPrevChildInlineFlow = true; - else - isPrevChildInlineFlow = false; - - oldAutoWrap = autoWrap; - } - - if (styleToUse->collapseWhiteSpace()) - stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild); - - updatePreferredWidth(minLogicalWidth, inlineMin); - updatePreferredWidth(maxLogicalWidth, inlineMax); -} - void RenderBlock::computeBlockPreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const { RenderStyle* styleToUse = style(); @@ -4491,7 +3745,7 @@ bool RenderBlock::hasLineIfEmpty() const if (node()->isRootEditableElement()) return true; - if (node()->isShadowRoot() && toShadowRoot(node())->host()->hasTagName(inputTag)) + if (node()->isShadowRoot() && isHTMLInputElement(*toShadowRoot(node())->host())) return true; return false; @@ -4506,16 +3760,13 @@ LayoutUnit RenderBlock::lineHeight(bool firstLine, LineDirectionMode direction, if (isReplaced() && linePositionMode == PositionOnContainingLine) return RenderBox::lineHeight(firstLine, direction, linePositionMode); - if (firstLine && document().styleEngine()->usesFirstLineRules()) { - RenderStyle* s = style(firstLine); - if (s != style()) - return s->computedLineHeight(view()); - } - - if (m_lineHeight == -1) - m_lineHeight = style()->computedLineHeight(view()); + RenderStyle* s = style(firstLine && document().styleEngine()->usesFirstLineRules()); + return s->computedLineHeight(); +} - return m_lineHeight; +int RenderBlock::beforeMarginInLineDirection(LineDirectionMode direction) const +{ + return direction == HorizontalLine ? marginTop() : marginRight(); } int RenderBlock::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const @@ -4524,7 +3775,7 @@ int RenderBlock::baselinePosition(FontBaseline baselineType, bool firstLine, Lin // the base class. If we're being queried as though we're the root line // box, then the fact that we're an inline-block is irrelevant, and we behave // just like a block. - if (isReplaced() && linePositionMode == PositionOnContainingLine) { + if (isInline() && linePositionMode == PositionOnContainingLine) { // For "leaf" theme objects, let the theme decide what the baseline position is. // FIXME: Might be better to have a custom CSS property instead, so that if the theme // is turned off, checkboxes/radios will still have decent baselines. @@ -4553,7 +3804,7 @@ int RenderBlock::baselinePosition(FontBaseline baselineType, bool firstLine, Lin baselinePos = -1; } if (baselinePos != -1) - return direction == HorizontalLine ? marginTop() + baselinePos : marginRight() + baselinePos; + return beforeMarginInLineDirection(direction) + baselinePos; return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode); } @@ -4603,7 +3854,7 @@ int RenderBlock::firstLineBoxBaseline() const int RenderBlock::inlineBlockBaseline(LineDirectionMode direction) const { - if (style()->overflowY() != OVISIBLE) { + if (!style()->isOverflowVisible()) { // We are not calling RenderBox::baselinePosition here because the caller should add the margin-top/margin-right, not us. return direction == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left(); } @@ -4663,10 +3914,12 @@ RenderBlock* RenderBlock::firstLineBlock() const // FIXME: Remove when buttons are implemented with align-items instead // of flexbox. if (firstLineBlock->isReplaced() || firstLineBlock->isFloating() - || !parentBlock || parentBlock->firstChild() != firstLineBlock + || !parentBlock || (!parentBlock->isRenderBlockFlow() && !parentBlock->isRenderButton())) break; ASSERT_WITH_SECURITY_IMPLICATION(parentBlock->isRenderBlock()); + if (toRenderBlock(parentBlock)->firstChild() != firstLineBlock) + break; firstLineBlock = toRenderBlock(parentBlock); } @@ -4699,9 +3952,9 @@ static inline bool isPunctuationForFirstLetter(UChar c) || charCategory == Punctuation_Other; } -static inline bool shouldSkipForFirstLetter(UChar c) +static inline bool isSpaceForFirstLetter(UChar c) { - return isSpaceOrNewline(c) || c == noBreakSpace || isPunctuationForFirstLetter(c); + return isSpaceOrNewline(c) || c == noBreakSpace; } static inline RenderObject* findFirstLetterBlock(RenderBlock* start) @@ -4721,8 +3974,12 @@ static inline RenderObject* findFirstLetterBlock(RenderBlock* start) return firstLetterBlock; RenderObject* parentBlock = firstLetterBlock->parent(); - if (firstLetterBlock->isReplaced() || !parentBlock || parentBlock->firstChild() != firstLetterBlock || - (!parentBlock->isRenderBlockFlow() && !parentBlock->isRenderButton())) + if (firstLetterBlock->isReplaced() || !parentBlock + || (!parentBlock->isRenderBlockFlow() && !parentBlock->isRenderButton())) { + return 0; + } + ASSERT(parentBlock->isRenderBlock()); + if (toRenderBlock(parentBlock)->firstChild() != firstLetterBlock) return 0; firstLetterBlock = parentBlock; } @@ -4737,7 +3994,9 @@ void RenderBlock::updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderO RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer); ASSERT(firstLetter->isFloating() || firstLetter->isInline()); - if (RenderStyle::compare(firstLetter->style(), pseudoStyle) == Reattach) { + ForceHorriblySlowRectMapping slowRectMapping(*this); + + if (RenderStyle::stylePropagationDiff(firstLetter->style(), pseudoStyle) == Reattach) { // The first-letter renderer needs to be replaced. Create a new renderer of the right type. RenderBoxModelObject* newFirstLetter; if (pseudoStyle->display() == INLINE) @@ -4747,8 +4006,7 @@ void RenderBlock::updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderO newFirstLetter->setStyle(pseudoStyle); // Move the first letter into the new renderer. - LayoutStateDisabler layoutStateDisabler(view()); - while (RenderObject* child = firstLetter->firstChild()) { + while (RenderObject* child = firstLetter->slowFirstChild()) { if (child->isText()) toRenderText(child)->removeAndDestroyTextBoxes(); firstLetter->removeChild(child); @@ -4771,7 +4029,7 @@ void RenderBlock::updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderO } else firstLetter->setStyle(pseudoStyle); - for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) { + for (RenderObject* genChild = firstLetter->slowFirstChild(); genChild; genChild = genChild->nextSibling()) { if (genChild->isText()) genChild->setStyle(pseudoStyle); } @@ -4780,38 +4038,34 @@ void RenderBlock::updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderO static inline unsigned firstLetterLength(const String& text) { unsigned length = 0; - bool punctuationOpen = false; + unsigned textLength = text.length(); - // Account for leading spaces and punctuation. - while (length < text.length() && shouldSkipForFirstLetter((text)[length])) { - if (isPunctuationForFirstLetter((text)[length])) - punctuationOpen = true; + // Account for leading spaces first. + while (length < textLength && isSpaceForFirstLetter(text[length])) + length++; + // Now account for leading punctuation. + while (length < textLength && isPunctuationForFirstLetter(text[length])) length++; - } - // Bail if we didn't find a letter - if (text.length() && length == text.length()) + // Bail if we didn't find a letter before the end of the text or before a space. + if (isSpaceForFirstLetter(text[length]) || (textLength && length == textLength)) return 0; - // Account for first letter. + // Account the next character for first letter. length++; - if (!punctuationOpen) - return length; - - // Keep looking for whitespace and allowed punctuation, but avoid - // accumulating just whitespace into the :first-letter. - for (unsigned scanLength = length; scanLength < text.length(); ++scanLength) { - UChar c = (text)[scanLength]; + // Keep looking allowed punctuation for the :first-letter. + for (unsigned scanLength = length; scanLength < textLength; ++scanLength) { + UChar c = text[scanLength]; - if (!shouldSkipForFirstLetter(c)) + if (!isPunctuationForFirstLetter(c)) break; - if (isPunctuationForFirstLetter(c)) - length = scanLength + 1; + length = scanLength + 1; } + // FIXME: If textLength is 0, length may still be 1! return length; } @@ -4821,14 +4075,18 @@ void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, Rend RenderObject* firstLetterContainer = currentChild->parent(); RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer); - RenderObject* firstLetter = 0; + RenderBoxModelObject* firstLetter = 0; if (pseudoStyle->display() == INLINE) firstLetter = RenderInline::createAnonymous(&document()); else firstLetter = RenderBlockFlow::createAnonymous(&document()); firstLetter->setStyle(pseudoStyle); - firstLetterContainer->addChild(firstLetter, currentChild); + // FIXME: The first letter code should not modify the render tree during + // layout. crbug.com/370458 + DeprecatedDisableModifyRenderTreeStructureAsserts disabler; + + 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 @@ -4848,7 +4106,7 @@ void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, Rend firstLetterContainer->addChild(remainingText, textObj); firstLetterContainer->removeChild(textObj); remainingText->setFirstLetter(firstLetter); - toRenderBoxModelObject(firstLetter)->setFirstLetterRemainingText(remainingText); + firstLetter->setFirstLetterRemainingText(remainingText); // construct text fragment for the first letter RenderTextFragment* letter = @@ -4874,7 +4132,7 @@ void RenderBlock::updateFirstLetter() return; // Drill into inlines looking for our first text child. - RenderObject* currChild = firstLetterBlock->firstChild(); + RenderObject* currChild = firstLetterBlock->slowFirstChild(); unsigned length = 0; while (currChild) { if (currChild->isText()) { @@ -4888,18 +4146,19 @@ void RenderBlock::updateFirstLetter() currChild = currChild->nextSibling(); } else if (currChild->isFloatingOrOutOfFlowPositioned()) { if (currChild->style()->styleType() == FIRST_LETTER) { - currChild = currChild->firstChild(); + currChild = currChild->slowFirstChild(); break; } currChild = currChild->nextSibling(); - } else if (currChild->isReplaced() || currChild->isRenderButton() || currChild->isMenuList()) + } else if (currChild->isReplaced() || currChild->isRenderButton() || currChild->isMenuList()) { break; - else if (currChild->style()->hasPseudoStyle(FIRST_LETTER) && currChild->canHaveGeneratedChildren()) { + } else if (currChild->style()->hasPseudoStyle(FIRST_LETTER) && currChild->canHaveGeneratedChildren()) { // We found a lower-level node with first-letter, which supersedes the higher-level style firstLetterBlock = currChild; - currChild = currChild->firstChild(); - } else - currChild = currChild->firstChild(); + currChild = currChild->slowFirstChild(); + } else { + currChild = currChild->slowFirstChild(); + } } if (!currChild) @@ -4912,12 +4171,14 @@ void RenderBlock::updateFirstLetter() return; } - if (!currChild->isText() || currChild->isBR()) + // FIXME: This black-list of disallowed RenderText subclasses is fragile. + // Should counter be on this list? What about RenderTextFragment? + if (!currChild->isText() || currChild->isBR() || toRenderText(currChild)->isWordBreak()) 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()); + ForceHorriblySlowRectMapping slowRectMapping(*this); createFirstLetterRenderer(firstLetterBlock, currChild, length); } @@ -5059,7 +4320,7 @@ void RenderBlock::fitBorderToLinesIfNeeded() LayoutUnit leftEdge = borderLeft() + paddingLeft(); LayoutUnit rightEdge = leftEdge + oldWidth; left = min(rightEdge, max(leftEdge, left)); - right = max(leftEdge, min(rightEdge, right)); + right = max(left, min(rightEdge, right)); LayoutUnit newContentWidth = right - left; if (newContentWidth == oldWidth) @@ -5168,17 +4429,18 @@ void RenderBlock::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const if (isAnonymousBlockContinuation()) { // FIXME: This is wrong for block-flows that are horizontal. // https://bugs.webkit.org/show_bug.cgi?id=46781 - FloatRect localRect(0, -collapsedMarginBefore(), - width(), height() + collapsedMarginBefore() + collapsedMarginAfter()); + FloatRect localRect(0, -collapsedMarginBefore().toFloat(), + width().toFloat(), (height() + collapsedMarginBefore() + collapsedMarginAfter()).toFloat()); quads.append(localToAbsoluteQuad(localRect, 0 /* mode */, wasFixed)); continuation()->absoluteQuads(quads, wasFixed); - } else - quads.append(RenderBox::localToAbsoluteQuad(FloatRect(0, 0, width(), height()), 0 /* mode */, wasFixed)); + } else { + quads.append(RenderBox::localToAbsoluteQuad(FloatRect(0, 0, width().toFloat(), height().toFloat()), 0 /* mode */, wasFixed)); + } } -LayoutRect RenderBlock::rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const +LayoutRect RenderBlock::rectWithOutlineForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, LayoutUnit outlineWidth) const { - LayoutRect r(RenderBox::rectWithOutlineForRepaint(repaintContainer, outlineWidth)); + LayoutRect r(RenderBox::rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineWidth)); if (isAnonymousBlockContinuation()) r.inflateY(collapsedMarginBefore()); // FIXME: This is wrong for block-flows that are horizontal. return r; @@ -5196,7 +4458,7 @@ void RenderBlock::updateDragState(bool dragOn) continuation()->updateDragState(dragOn); } -RenderStyle* RenderBlock::outlineStyleForRepaint() const +RenderStyle* RenderBlock::outlineStyleForPaintInvalidation() const { return isAnonymousBlockContinuation() ? continuation()->style() : style(); } @@ -5240,10 +4502,10 @@ LayoutRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, La LayoutUnit myRight = caretRect.maxX(); // FIXME: why call localToAbsoluteForContent() twice here, too? - FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0)); + FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight.toFloat(), 0)); LayoutUnit containerRight = containingBlock()->x() + containingBlockLogicalWidthForContent(); - FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0)); + FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight.toFloat(), 0)); *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x(); } @@ -5264,8 +4526,8 @@ void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& a // FIXME: This is wrong for block-flows that are horizontal. // https://bugs.webkit.org/show_bug.cgi?id=46781 bool prevInlineHasLineBox = toRenderInline(inlineElementContinuation()->node()->renderer())->firstLineBox(); - float topMargin = prevInlineHasLineBox ? collapsedMarginBefore() : LayoutUnit(); - float bottomMargin = nextInlineHasLineBox ? collapsedMarginAfter() : LayoutUnit(); + LayoutUnit topMargin = prevInlineHasLineBox ? collapsedMarginBefore() : LayoutUnit(); + LayoutUnit bottomMargin = nextInlineHasLineBox ? collapsedMarginAfter() : LayoutUnit(); LayoutRect rect(additionalOffset.x(), additionalOffset.y() - topMargin, width(), height() + topMargin + bottomMargin); if (!rect.isEmpty()) rects.append(pixelSnappedIntRect(rect)); @@ -5281,18 +4543,7 @@ void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& a rects.append(pixelSnappedIntRect(rect)); } - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - if (!curr->isText() && !curr->isListMarker() && curr->isBox()) { - RenderBox* box = toRenderBox(curr); - FloatPoint pos; - // FIXME: This doesn't work correctly with transforms. - if (box->layer()) - pos = curr->localToContainerPoint(FloatPoint(), paintContainer); - else - pos = FloatPoint(additionalOffset.x() + box->x(), additionalOffset.y() + box->y()); - box->addFocusRingRects(rects, flooredLayoutPoint(pos), paintContainer); - } - } + addChildFocusRingRects(rects, additionalOffset, paintContainer); } if (inlineElementContinuation()) @@ -5324,25 +4575,6 @@ RenderBox* RenderBlock::createAnonymousBoxWithSameTypeAs(const RenderObject* par return createAnonymousWithParentRendererAndDisplay(parent, style()->display()); } -bool RenderBlock::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const -{ - ASSERT(view()->layoutState() && view()->layoutState()->isPaginated()); - - RenderFlowThread* flowThread = flowThreadContainingBlock(); - if (!flowThread) - return true; // Printing and multi-column both make new pages to accommodate content. - - // See if we're in the last region. - LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset; - RenderRegion* region = flowThread->regionAtBlockOffset(pageOffset, this); - if (!region) - return false; - if (region->isLastRegion()) - return region->isRenderRegionSet() || region->style()->regionFragment() == BreakRegionFragment - || (pageBoundaryRule == IncludePageBoundary && pageOffset == region->logicalTopForFlowThreadContent()); - return true; -} - LayoutUnit RenderBlock::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const { LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset); @@ -5356,16 +4588,11 @@ LayoutUnit RenderBlock::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundar return logicalOffset + remainingLogicalHeight; } -ColumnInfo::PaginationUnit RenderBlock::paginationUnit() const -{ - return ColumnInfo::Column; -} - LayoutUnit RenderBlock::pageLogicalTopForOffset(LayoutUnit offset) const { RenderView* renderView = view(); - LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_pageOffset.height() : renderView->layoutState()->m_pageOffset.width(); - LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_layoutOffset.height() : renderView->layoutState()->m_layoutOffset.width(); + LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->pageOffset().height() : renderView->layoutState()->pageOffset().width(); + LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->layoutOffset().height() : renderView->layoutState()->layoutOffset().width(); LayoutUnit cumulativeOffset = offset + blockLogicalTop; RenderFlowThread* flowThread = flowThreadContainingBlock(); @@ -5383,7 +4610,7 @@ LayoutUnit RenderBlock::pageLogicalHeightForOffset(LayoutUnit offset) const RenderView* renderView = view(); RenderFlowThread* flowThread = flowThreadContainingBlock(); if (!flowThread) - return renderView->layoutState()->m_pageLogicalHeight; + return renderView->layoutState()->pageLogicalHeight(); return flowThread->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage()); } @@ -5394,7 +4621,7 @@ LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, P RenderFlowThread* flowThread = flowThreadContainingBlock(); if (!flowThread) { - LayoutUnit pageLogicalHeight = renderView->layoutState()->m_pageLogicalHeight; + LayoutUnit pageLogicalHeight = renderView->layoutState()->pageLogicalHeight(); LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight); if (pageBoundaryRule == IncludePageBoundary) { // If includeBoundaryPoint is true the line exactly on the top edge of a @@ -5409,46 +4636,23 @@ LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, P LayoutUnit RenderBlock::adjustForUnsplittableChild(RenderBox* child, LayoutUnit logicalOffset, bool includeMargins) { - bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns(); - bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; - RenderFlowThread* flowThread = flowThreadContainingBlock(); - bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread(); + bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns() || flowThreadContainingBlock(); + bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->pageLogicalHeight(); bool isUnsplittable = child->isUnsplittableForPagination() || (checkColumnBreaks && child->style()->columnBreakInside() == PBAVOID) - || (checkPageBreaks && child->style()->pageBreakInside() == PBAVOID) - || (checkRegionBreaks && child->style()->regionBreakInside() == PBAVOID); + || (checkPageBreaks && child->style()->pageBreakInside() == PBAVOID); if (!isUnsplittable) return logicalOffset; LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit()); LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset); - bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight(); updateMinimumPageHeight(logicalOffset, childLogicalHeight); - if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight) - || !hasNextPage(logicalOffset)) + if (!pageLogicalHeight || childLogicalHeight > pageLogicalHeight) return logicalOffset; LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary); - if (remainingLogicalHeight < childLogicalHeight) { - if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight)) - return logicalOffset; + if (remainingLogicalHeight < childLogicalHeight) return logicalOffset + remainingLogicalHeight; - } return logicalOffset; } -bool RenderBlock::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const -{ - bool checkRegion = false; - for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight; - pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) { - if (minimumLogicalHeight <= pageLogicalHeight) - return true; - if (!hasNextPage(logicalOffset + adjustment)) - return false; - adjustment += pageLogicalHeight; - checkRegion = true; - } - return !checkRegion; -} - void RenderBlock::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage) { if (RenderFlowThread* flowThread = flowThreadContainingBlock()) @@ -5459,7 +4663,7 @@ void RenderBlock::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeigh { if (RenderFlowThread* flowThread = flowThreadContainingBlock()) flowThread->updateMinimumPageHeight(offsetFromLogicalTopOfFirstPage() + offset, minHeight); - else if (ColumnInfo* colInfo = view()->layoutState()->m_columnInfo) + else if (ColumnInfo* colInfo = view()->layoutState()->columnInfo()) colInfo->updateMinimumColumnHeight(minHeight); } @@ -5514,8 +4718,7 @@ void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, Layout bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight(); // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are // still going to add a strut, so that the visible overflow fits on a single page. - if (!pageLogicalHeight || (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight) - || !hasNextPage(logicalOffset)) + if (!pageLogicalHeight || (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight)) // FIXME: In case the line aligns with the top of the page (or it's slightly shifted downwards) it will not be marked as the first line in the page. // From here, the fix is not straightforward because it's not easy to always determine when the current line is the first in the page. return; @@ -5527,9 +4730,6 @@ void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, Layout clearShouldBreakAtLineToAvoidWidow(); setDidBreakAtLineToAvoidWidow(); } - // If we have a non-uniform page height, then we have to shift further possibly. - if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight)) - return; if (lineHeight > pageLogicalHeight) { // Split the top margin in order to avoid splitting the visible part of the line. remainingLogicalHeight -= min(lineHeight - pageLogicalHeight, max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading())); @@ -5554,34 +4754,6 @@ void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, Layout } } -void RenderBlock::updateRegionForLine(RootInlineBox* lineBox) const -{ - ASSERT(lineBox); - lineBox->setContainingRegion(regionAtBlockOffset(lineBox->lineTopWithLeading())); - - RootInlineBox* prevLineBox = lineBox->prevRootBox(); - if (!prevLineBox) - return; - - // This check is more accurate than the one in |adjustLinePositionForPagination| because it takes into - // account just the container changes between lines. The before mentioned function doesn't set the flag - // correctly if the line is positioned at the top of the last fragment container. - if (lineBox->containingRegion() != prevLineBox->containingRegion()) - lineBox->setIsFirstAfterPageBreak(true); -} - -bool RenderBlock::lineWidthForPaginatedLineChanged(RootInlineBox* rootBox, LayoutUnit lineDelta, RenderFlowThread* flowThread) const -{ - if (!flowThread) - return false; - - RenderRegion* currentRegion = regionAtBlockOffset(rootBox->lineTopWithLeading() + lineDelta); - // Just bail if the region didn't change. - if (rootBox->containingRegion() == currentRegion) - return false; - return rootBox->paginatedLineWidth() != availableLogicalWidthForContent(currentRegion); -} - LayoutUnit RenderBlock::offsetFromLogicalTopOfFirstPage() const { LayoutState* layoutState = view()->layoutState(); @@ -5595,7 +4767,7 @@ LayoutUnit RenderBlock::offsetFromLogicalTopOfFirstPage() const if (layoutState) { ASSERT(layoutState->renderer() == this); - LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset; + LayoutSize offsetDelta = layoutState->layoutOffset() - layoutState->pageOffset(); return isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width(); } @@ -5603,47 +4775,6 @@ LayoutUnit RenderBlock::offsetFromLogicalTopOfFirstPage() const return 0; } -RenderRegion* RenderBlock::regionAtBlockOffset(LayoutUnit blockOffset) const -{ - RenderFlowThread* flowThread = flowThreadContainingBlock(); - if (!flowThread || !flowThread->hasValidRegionInfo()) - return 0; - - return flowThread->regionAtBlockOffset(offsetFromLogicalTopOfFirstPage() + blockOffset, true); -} - -bool RenderBlock::logicalWidthChangedInRegions(RenderFlowThread* flowThread) const -{ - if (!flowThread || !flowThread->hasValidRegionInfo()) - return false; - - return flowThread->logicalWidthChangedInRegionsForBlock(this); -} - -RenderRegion* RenderBlock::clampToStartAndEndRegions(RenderRegion* region) const -{ - RenderFlowThread* flowThread = flowThreadContainingBlock(); - - ASSERT(isRenderView() || (region && flowThread)); - if (isRenderView()) - return region; - - // We need to clamp to the block, since we want any lines or blocks that overflow out of the - // logical top or logical bottom of the block to size as though the border box in the first and - // last regions extended infinitely. Otherwise the lines are going to size according to the regions - // they overflow into, which makes no sense when this block doesn't exist in |region| at all. - RenderRegion* startRegion; - RenderRegion* endRegion; - flowThread->getRegionRangeForBox(this, startRegion, endRegion); - - if (startRegion && region->logicalTopForFlowThreadContent() < startRegion->logicalTopForFlowThreadContent()) - return startRegion; - if (endRegion && region->logicalTopForFlowThreadContent() > endRegion->logicalTopForFlowThreadContent()) - return endRegion; - - return region; -} - LayoutUnit RenderBlock::collapsedMarginBeforeForChild(const RenderBox* child) const { // If the child has the same directionality as we do, then we can just return its @@ -5781,6 +4912,91 @@ RenderBlockFlow* RenderBlock::createAnonymousColumnSpanWithParentRenderer(const return newBox; } +static bool recalcNormalFlowChildOverflowIfNeeded(RenderObject* renderer) +{ + if (renderer->isOutOfFlowPositioned() || !renderer->needsOverflowRecalcAfterStyleChange()) + return false; + + ASSERT(renderer->isRenderBlock()); + return toRenderBlock(renderer)->recalcOverflowAfterStyleChange(); +} + +bool RenderBlock::recalcChildOverflowAfterStyleChange() +{ + ASSERT(childNeedsOverflowRecalcAfterStyleChange()); + setChildNeedsOverflowRecalcAfterStyleChange(false); + + bool childrenOverflowChanged = false; + + if (childrenInline()) { + ListHashSet<RootInlineBox*> lineBoxes; + for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) { + RenderObject* renderer = walker.current(); + if (recalcNormalFlowChildOverflowIfNeeded(renderer)) { + childrenOverflowChanged = true; + if (InlineBox* inlineBoxWrapper = toRenderBlock(renderer)->inlineBoxWrapper()) + lineBoxes.add(&inlineBoxWrapper->root()); + } + } + + // FIXME: Glyph overflow will get lost in this case, but not really a big deal. + GlyphOverflowAndFallbackFontsMap textBoxDataMap; + for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) { + RootInlineBox* box = *it; + box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap); + } + } else { + for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) { + if (recalcNormalFlowChildOverflowIfNeeded(box)) + childrenOverflowChanged = true; + } + } + + TrackedRendererListHashSet* positionedDescendants = positionedObjects(); + if (!positionedDescendants) + return childrenOverflowChanged; + + TrackedRendererListHashSet::iterator end = positionedDescendants->end(); + for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) { + RenderBox* box = *it; + + if (!box->needsOverflowRecalcAfterStyleChange()) + continue; + RenderBlock* block = toRenderBlock(box); + if (!block->recalcOverflowAfterStyleChange() || box->style()->position() == FixedPosition) + continue; + + childrenOverflowChanged = true; + } + return childrenOverflowChanged; +} + +bool RenderBlock::recalcOverflowAfterStyleChange() +{ + ASSERT(needsOverflowRecalcAfterStyleChange()); + + bool childrenOverflowChanged = false; + if (childNeedsOverflowRecalcAfterStyleChange()) + childrenOverflowChanged = recalcChildOverflowAfterStyleChange(); + + if (!selfNeedsOverflowRecalcAfterStyleChange() && !childrenOverflowChanged) + return false; + + setSelfNeedsOverflowRecalcAfterStyleChange(false); + // If the current block needs layout, overflow will be recalculated during + // layout time anyway. We can safely exit here. + if (needsLayout()) + return false; + + LayoutUnit oldClientAfterEdge = hasRenderOverflow() ? m_overflow->layoutClientAfterEdge() : clientLogicalBottom(); + computeOverflow(oldClientAfterEdge, true); + + if (hasOverflowClip()) + layer()->scrollableArea()->updateAfterOverflowRecalc(); + + return !hasOverflowClip(); +} + #ifndef NDEBUG void RenderBlock::checkPositionedObjectsNeedLayout() { diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderBlock.h b/chromium/third_party/WebKit/Source/core/rendering/RenderBlock.h index cd090231993..c3ce2fb32a9 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderBlock.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderBlock.h @@ -29,7 +29,6 @@ #include "core/rendering/RenderBox.h" #include "core/rendering/RenderLineBoxList.h" #include "core/rendering/RootInlineBox.h" -#include "core/rendering/shapes/ShapeInsideInfo.h" #include "core/rendering/style/ShapeValue.h" #include "platform/text/TextBreakIterator.h" #include "platform/text/TextRun.h" @@ -38,32 +37,21 @@ namespace WebCore { -class BasicShape; -class BidiContext; -class InlineIterator; -class LayoutStateMaintainer; class LineLayoutState; class RenderInline; -class RenderText; -struct BidiRun; struct PaintInfo; +class WordMeasurement; + class LineInfo; class RenderRubyRun; -class TextLayout; -class WordMeasurement; -template <class Iterator, class Run> class BidiResolver; template <class Run> class BidiRunList; -template <class Iterator> struct MidpointState; -typedef BidiResolver<InlineIterator, BidiRun> InlineBidiResolver; -typedef MidpointState<InlineIterator> LineMidpointState; typedef WTF::ListHashSet<RenderBox*, 16> TrackedRendererListHashSet; typedef WTF::HashMap<const RenderBlock*, OwnPtr<TrackedRendererListHashSet> > TrackedDescendantsMap; typedef WTF::HashMap<const RenderBox*, OwnPtr<HashSet<RenderBlock*> > > TrackedContainerMap; typedef Vector<WordMeasurement, 64> WordMeasurements; -enum CaretType { CursorCaret, DragCaret }; enum ContainingBlockState { NewContainingBlock, SameContainingBlock }; enum TextRunFlag { @@ -86,6 +74,10 @@ public: RenderObject* firstChild() const { ASSERT(children() == virtualChildren()); return children()->firstChild(); } RenderObject* lastChild() const { ASSERT(children() == virtualChildren()); return children()->lastChild(); } + // If you have a RenderBlock, use firstChild or lastChild instead. + void slowFirstChild() const WTF_DELETED_FUNCTION; + void slowLastChild() const WTF_DELETED_FUNCTION; + const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } @@ -93,7 +85,7 @@ public: // These two functions are overridden for inline-block. virtual LayoutUnit lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const OVERRIDE FINAL; - virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const; + virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const OVERRIDE; LayoutUnit minLineHeightForReplacedRenderer(bool isFirstLine, LayoutUnit replacedHeight) const; @@ -105,10 +97,10 @@ public: // FIXME-BLOCKFLOW: Remove virtualizaion when all callers have moved to RenderBlockFlow virtual void deleteLineBoxTree(); - virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); - virtual void removeChild(RenderObject*); + virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0) OVERRIDE; + virtual void removeChild(RenderObject*) OVERRIDE; - virtual void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0); + virtual void layoutBlock(bool relayoutChildren); void insertPositionedObject(RenderBox*); static void removePositionedObject(RenderBox*); @@ -123,12 +115,18 @@ public: void addPercentHeightDescendant(RenderBox*); static void removePercentHeightDescendant(RenderBox*); - TrackedRendererListHashSet* percentHeightDescendants() const; static bool hasPercentHeightContainerMap(); static bool hasPercentHeightDescendant(RenderBox*); static void clearPercentHeightDescendantsFrom(RenderBox*); static void removePercentHeightDescendantIfNeeded(RenderBox*); + TrackedRendererListHashSet* percentHeightDescendants() const; + bool hasPercentHeightDescendants() const + { + TrackedRendererListHashSet* descendants = percentHeightDescendants(); + return descendants && !descendants->isEmpty(); + } + void setHasMarkupTruncation(bool b) { m_hasMarkupTruncation = b; } bool hasMarkupTruncation() const { return m_hasMarkupTruncation; } @@ -141,9 +139,6 @@ public: bool hasMarginBeforeQuirk(const RenderBox* child) const; bool hasMarginAfterQuirk(const RenderBox* child) const; - RootInlineBox* createAndAppendRootInlineBox(); - - void markShapeInsideDescendantsForLayout(); void markPositionedObjectsForLayout(); // FIXME: Do we really need this to be virtual? It's just so we can call this on // RenderBoxes without needed to check whether they're RenderBlocks first. @@ -152,67 +147,6 @@ public: // FIXME-BLOCKFLOW: Remove virtualizaion when all of the line layout code has been moved out of RenderBlock virtual bool containsFloats() const { return false; } - // Versions that can compute line offsets with the region and page offset passed in. Used for speed to avoid having to - // compute the region all over again when you already know it. - LayoutUnit availableLogicalWidthForLineInRegion(LayoutUnit position, bool shouldIndentText, RenderRegion* region, LayoutUnit logicalHeight = 0) const - { - return max<LayoutUnit>(0, logicalRightOffsetForLineInRegion(position, shouldIndentText, region, logicalHeight) - - logicalLeftOffsetForLineInRegion(position, shouldIndentText, region, logicalHeight)); - } - LayoutUnit logicalRightOffsetForLineInRegion(LayoutUnit position, bool shouldIndentText, RenderRegion* region, LayoutUnit logicalHeight = 0) const - { - return logicalRightOffsetForLine(position, logicalRightOffsetForContent(region), shouldIndentText, logicalHeight); - } - LayoutUnit logicalLeftOffsetForLineInRegion(LayoutUnit position, bool shouldIndentText, RenderRegion* region, LayoutUnit logicalHeight = 0) const - { - return logicalLeftOffsetForLine(position, logicalLeftOffsetForContent(region), shouldIndentText, logicalHeight); - } - LayoutUnit startOffsetForLineInRegion(LayoutUnit position, bool shouldIndentText, RenderRegion* region, LayoutUnit logicalHeight = 0) const - { - return style()->isLeftToRightDirection() ? logicalLeftOffsetForLineInRegion(position, shouldIndentText, region, logicalHeight) - : logicalWidth() - logicalRightOffsetForLineInRegion(position, shouldIndentText, region, logicalHeight); - } - LayoutUnit endOffsetForLineInRegion(LayoutUnit position, bool shouldIndentText, RenderRegion* region, LayoutUnit logicalHeight = 0) const - { - return !style()->isLeftToRightDirection() ? logicalLeftOffsetForLineInRegion(position, shouldIndentText, region, logicalHeight) - : logicalWidth() - logicalRightOffsetForLineInRegion(position, shouldIndentText, region, logicalHeight); - } - - LayoutUnit availableLogicalWidthForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const - { - return availableLogicalWidthForLineInRegion(position, shouldIndentText, regionAtBlockOffset(position), logicalHeight); - } - LayoutUnit logicalRightOffsetForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const - { - return logicalRightOffsetForLine(position, logicalRightOffsetForContent(position), shouldIndentText, logicalHeight); - } - LayoutUnit logicalLeftOffsetForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const - { - return logicalLeftOffsetForLine(position, logicalLeftOffsetForContent(position), shouldIndentText, logicalHeight); - } - LayoutUnit pixelSnappedLogicalLeftOffsetForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const - { - return roundToInt(logicalLeftOffsetForLine(position, shouldIndentText, logicalHeight)); - } - LayoutUnit pixelSnappedLogicalRightOffsetForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) 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. - // https://bugs.webkit.org/show_bug.cgi?id=105461 - return floorToInt(logicalRightOffsetForLine(position, shouldIndentText, logicalHeight)); - } - LayoutUnit startOffsetForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const - { - return style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(position, shouldIndentText, logicalHeight) - : logicalWidth() - logicalRightOffsetForLine(position, shouldIndentText, logicalHeight); - } - LayoutUnit endOffsetForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const - { - return !style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(position, shouldIndentText, logicalHeight) - : logicalWidth() - logicalRightOffsetForLine(position, shouldIndentText, logicalHeight); - } - LayoutUnit textIndentOffset() const; virtual PositionWithAffinity positionForPoint(const LayoutPoint&) OVERRIDE; @@ -229,6 +163,7 @@ public: RootInlineBox* firstRootBox() const { return static_cast<RootInlineBox*>(firstLineBox()); } RootInlineBox* lastRootBox() const { return static_cast<RootInlineBox*>(lastLineBox()); } + virtual bool shouldPaintSelectionGaps() const OVERRIDE FINAL; GapRects selectionGapRectsForRepaint(const RenderLayerModelObject* repaintContainer); LayoutRect logicalLeftSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo*); @@ -246,7 +181,7 @@ public: void clearTruncation(); void adjustRectForColumns(LayoutRect&) const; - virtual void adjustForColumns(LayoutSize&, const LayoutPoint&) const OVERRIDE FINAL; + virtual LayoutSize columnOffset(const LayoutPoint&) const OVERRIDE; void adjustForColumnRect(LayoutSize& offset, const LayoutPoint& locationInContainer) const; void addContinuationWithOutline(RenderInline*); @@ -272,8 +207,6 @@ public: ColumnInfo* columnInfo() const; int columnGap() const; - void updateColumnInfoFromStyle(RenderStyle*); - // These two functions take the ColumnInfo* to avoid repeated lookups of the info in the global HashMap. unsigned columnCount(ColumnInfo*) const; LayoutRect columnRectAt(ColumnInfo*, unsigned) const; @@ -295,12 +228,10 @@ public: void setPageLogicalOffset(LayoutUnit); // Accessors for logical width/height and margins in the containing block's block-flow direction. - enum ApplyLayoutDeltaMode { ApplyLayoutDelta, DoNotApplyLayoutDelta }; LayoutUnit logicalWidthForChild(const RenderBox* child) const { return isHorizontalWritingMode() ? child->width() : child->height(); } LayoutUnit logicalHeightForChild(const RenderBox* child) const { return isHorizontalWritingMode() ? child->height() : child->width(); } + LayoutSize logicalSizeForChild(const RenderBox* child) const { return isHorizontalWritingMode() ? child->size() : child->size().transposedSize(); } LayoutUnit logicalTopForChild(const RenderBox* child) const { return isHorizontalWritingMode() ? child->y() : child->x(); } - void setLogicalLeftForChild(RenderBox* child, LayoutUnit logicalLeft, ApplyLayoutDeltaMode = DoNotApplyLayoutDelta); - void setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop, ApplyLayoutDeltaMode = DoNotApplyLayoutDelta); LayoutUnit marginBeforeForChild(const RenderBoxModelObject* child) const { return child->marginBefore(style()); } LayoutUnit marginAfterForChild(const RenderBoxModelObject* child) const { return child->marginAfter(style()); } LayoutUnit marginStartForChild(const RenderBoxModelObject* child) const { return child->marginStart(style()); } @@ -313,125 +244,67 @@ public: LayoutUnit collapsedMarginAfterForChild(const RenderBox* child) const; virtual void updateFirstLetter(); + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; - virtual void scrollbarsChanged(bool /*horizontalScrollbarChanged*/, bool /*verticalScrollbarChanged*/) { }; + virtual void scrollbarsChanged(bool /*horizontalScrollbarChanged*/, bool /*verticalScrollbarChanged*/) { } - LayoutUnit logicalLeftOffsetForContent(RenderRegion*) const; - LayoutUnit logicalRightOffsetForContent(RenderRegion*) const; - LayoutUnit availableLogicalWidthForContent(RenderRegion* region) const - { - return max<LayoutUnit>(0, logicalRightOffsetForContent(region) - logicalLeftOffsetForContent(region)); - } - LayoutUnit startOffsetForContent(RenderRegion* region) const - { - return style()->isLeftToRightDirection() ? logicalLeftOffsetForContent(region) : logicalWidth() - logicalRightOffsetForContent(region); - } - LayoutUnit endOffsetForContent(RenderRegion* region) const - { - return !style()->isLeftToRightDirection() ? logicalLeftOffsetForContent(region) : logicalWidth() - logicalRightOffsetForContent(region); - } - LayoutUnit logicalLeftOffsetForContent(LayoutUnit blockOffset) const - { - return logicalLeftOffsetForContent(regionAtBlockOffset(blockOffset)); - } - LayoutUnit logicalRightOffsetForContent(LayoutUnit blockOffset) const - { - return logicalRightOffsetForContent(regionAtBlockOffset(blockOffset)); - } - LayoutUnit availableLogicalWidthForContent(LayoutUnit blockOffset) const - { - return availableLogicalWidthForContent(regionAtBlockOffset(blockOffset)); - } - LayoutUnit startOffsetForContent(LayoutUnit blockOffset) const - { - return startOffsetForContent(regionAtBlockOffset(blockOffset)); - } - LayoutUnit endOffsetForContent(LayoutUnit blockOffset) const - { - return endOffsetForContent(regionAtBlockOffset(blockOffset)); - } + LayoutUnit availableLogicalWidthForContent() const { return max<LayoutUnit>(0, logicalRightOffsetForContent() - logicalLeftOffsetForContent()); } LayoutUnit logicalLeftOffsetForContent() const { return isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop(); } LayoutUnit logicalRightOffsetForContent() const { return logicalLeftOffsetForContent() + availableLogicalWidth(); } LayoutUnit startOffsetForContent() const { return style()->isLeftToRightDirection() ? logicalLeftOffsetForContent() : logicalWidth() - logicalRightOffsetForContent(); } LayoutUnit endOffsetForContent() const { return !style()->isLeftToRightDirection() ? logicalLeftOffsetForContent() : logicalWidth() - logicalRightOffsetForContent(); } - LayoutUnit computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart, RenderRegion* = 0); - #ifndef NDEBUG void checkPositionedObjectsNeedLayout(); void showLineTreeAndMark(const InlineBox* = 0, const char* = 0, const InlineBox* = 0, const char* = 0, const RenderObject* = 0) const; #endif - ShapeInsideInfo* ensureShapeInsideInfo() - { - if (!m_rareData || !m_rareData->m_shapeInsideInfo) - setShapeInsideInfo(ShapeInsideInfo::createInfo(this)); - return m_rareData->m_shapeInsideInfo.get(); - } - ShapeInsideInfo* shapeInsideInfo() const - { - return m_rareData && m_rareData->m_shapeInsideInfo && ShapeInsideInfo::isEnabledFor(this) ? m_rareData->m_shapeInsideInfo.get() : 0; - } - void setShapeInsideInfo(PassOwnPtr<ShapeInsideInfo> value) - { - if (!m_rareData) - m_rareData = adoptPtr(new RenderBlockRareData()); - m_rareData->m_shapeInsideInfo = value; - } - ShapeInsideInfo* layoutShapeInsideInfo() const; - bool allowsShapeInsideInfoSharing(const RenderBlock* other) const; - LayoutSize logicalOffsetFromShapeAncestorContainer(const RenderBlock* container) const; - virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) OVERRIDE; - // inline-block elements paint all phases atomically. This function ensures that. Certain other elements // (grid items, flex items) require this behavior as well, and this function exists as a helper for them. // It is expected that the caller will call this function independent of the value of paintInfo.phase. static void paintAsInlineBlock(RenderObject*, PaintInfo&, const LayoutPoint&); + + bool recalcChildOverflowAfterStyleChange(); + bool recalcOverflowAfterStyleChange(); + protected: - virtual void willBeDestroyed(); + virtual void willBeDestroyed() OVERRIDE; void dirtyForLayoutFromPercentageHeightDescendants(SubtreeLayoutScope&); - virtual void layout(); - virtual void didLayout(ResourceLoadPriorityOptimizer&); - virtual void didScroll(ResourceLoadPriorityOptimizer&); - void updateStyleImageLoadingPriorities(ResourceLoadPriorityOptimizer&); + virtual void layout() OVERRIDE; + virtual bool updateImageLoadingPriorities() OVERRIDE FINAL; + + enum PositionedLayoutBehavior { + DefaultLayout, + LayoutOnlyFixedPositionedObjects, + ForcedLayoutAfterContainingBlockMoved + }; - void layoutPositionedObjects(bool relayoutChildren, bool fixedPositionObjectsOnly = false); + void layoutPositionedObjects(bool relayoutChildren, PositionedLayoutBehavior = DefaultLayout); void markFixedPositionObjectForLayoutIfNeeded(RenderObject* child, SubtreeLayoutScope&); LayoutUnit marginIntrinsicLogicalWidthForChild(RenderBox* child) const; - virtual bool supportsPartialLayout() const OVERRIDE { return true; }; + int beforeMarginInLineDirection(LineDirectionMode) const; - virtual void paint(PaintInfo&, const LayoutPoint&); - virtual void paintObject(PaintInfo&, const LayoutPoint&); + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; + virtual void paintObject(PaintInfo&, const LayoutPoint&) OVERRIDE; virtual void paintChildren(PaintInfo&, const LayoutPoint&); void paintChild(RenderBox*, PaintInfo&, const LayoutPoint&); void paintChildAsInlineBlock(RenderBox*, PaintInfo&, const LayoutPoint&); - LayoutUnit logicalRightOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit logicalHeight = 0) const - { - return adjustLogicalRightOffsetForLine(logicalRightFloatOffsetForLine(logicalTop, fixedOffset, logicalHeight), applyTextIndent); - } - LayoutUnit logicalLeftOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit logicalHeight = 0) const - { - return adjustLogicalLeftOffsetForLine(logicalLeftFloatOffsetForLine(logicalTop, fixedOffset, logicalHeight), applyTextIndent); - } - - virtual void adjustInlineDirectionLineBounds(int /* expansionOpportunityCount */, float& /* logicalLeft */, float& /* logicalWidth */) const { } - - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual void adjustInlineDirectionLineBounds(unsigned /* expansionOpportunityCount */, float& /* logicalLeft */, float& /* logicalWidth */) const { } virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE; virtual void computePreferredLogicalWidths() OVERRIDE; void adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const; - virtual int firstLineBoxBaseline() const; + virtual int firstLineBoxBaseline() const OVERRIDE; virtual int inlineBlockBaseline(LineDirectionMode) const OVERRIDE; int lastLineBoxBaseline(LineDirectionMode) const; - virtual void updateHitTestResult(HitTestResult&, const LayoutPoint&); + virtual void updateHitTestResult(HitTestResult&, const LayoutPoint&) OVERRIDE; // Delay update scrollbar until finishDelayRepaint() will be // called. This function is used when a flexbox is laying out its @@ -443,8 +316,8 @@ protected: void updateScrollInfoAfterLayout(); - virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleWillChange(StyleDifference, const RenderStyle& newStyle) OVERRIDE; + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; virtual bool hasLineIfEmpty() const; @@ -465,32 +338,19 @@ protected: virtual void computeSelfHitTestRects(Vector<LayoutRect>&, const LayoutPoint& layerOffset) const OVERRIDE; - bool updateRegionsAndShapesLogicalSize(RenderFlowThread*); void computeRegionRangeForBlock(RenderFlowThread*); void updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, RenderBox*); - virtual void checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight); - virtual bool isInlineBlockOrInlineTable() const OVERRIDE FINAL { return isInline() && isReplaced(); } -private: - // FIXME-BLOCKFLOW: Remove virtualizaion when all callers have moved to RenderBlockFlow - virtual LayoutUnit logicalRightFloatOffsetForLine(LayoutUnit, LayoutUnit fixedOffset, LayoutUnit) const { return fixedOffset; } - // FIXME-BLOCKFLOW: Remove virtualizaion when all callers have moved to RenderBlockFlow - virtual LayoutUnit logicalLeftFloatOffsetForLine(LayoutUnit, LayoutUnit fixedOffset, LayoutUnit) const { return fixedOffset; } - LayoutUnit adjustLogicalRightOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const; - LayoutUnit adjustLogicalLeftOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const; - - void computeShapeSize(); - void updateRegionsAndShapesAfterChildLayout(RenderFlowThread*, bool); - void updateShapeInsideInfoAfterStyleChange(const ShapeValue*, const ShapeValue* oldShape); - void relayoutShapeDescendantIfMoved(RenderBlock* child, LayoutSize offset); + virtual void invalidateTreeAfterLayout(const RenderLayerModelObject&) OVERRIDE; +private: virtual RenderObjectChildList* virtualChildren() OVERRIDE FINAL { return children(); } virtual const RenderObjectChildList* virtualChildren() const OVERRIDE FINAL { return children(); } - virtual const char* renderName() const; + virtual const char* renderName() const OVERRIDE; virtual bool isRenderBlock() const OVERRIDE FINAL { return true; } @@ -498,27 +358,20 @@ private: virtual void removeLeftoverAnonymousBlock(RenderBlock* child); static void collapseAnonymousBlockChild(RenderBlock* parent, RenderBlock* child); - // FIXME-BLOCKFLOW: Remove virtualizaion when all callers have moved to RenderBlockFlow - virtual void moveAllChildrenIncludingFloatsTo(RenderBlock* toBlock, bool fullRemoveInsert) { moveAllChildrenTo(toBlock, fullRemoveInsert); } virtual void dirtyLinesFromChangedChild(RenderObject* child) OVERRIDE FINAL { m_lineBoxes.dirtyLinesFromChangedChild(this, child); } void addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild); - void addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild); + virtual void addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild) OVERRIDE; void addChildToAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild); void addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild = 0); - virtual bool isSelfCollapsingBlock() const OVERRIDE FINAL; + virtual bool isSelfCollapsingBlock() const OVERRIDE; void insertIntoTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*&, TrackedContainerMap*&); static void removeFromTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*&, TrackedContainerMap*&); - virtual RootInlineBox* createRootInlineBox() { return 0; } // Subclassed by RenderBlockFlow, SVG and Ruby. - - // Called to lay out the legend for a fieldset or the ruby text of a ruby run. - virtual RenderObject* layoutSpecialExcludedChild(bool /*relayoutChildren*/, SubtreeLayoutScope&) { return 0; } - void createFirstLetterRenderer(RenderObject* firstLetterBlock, RenderObject* currentChild, unsigned length); void updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderObject* firstLetterContainer); @@ -530,12 +383,11 @@ private: void paintColumnContents(PaintInfo&, const LayoutPoint&, bool paintFloats = false); void paintColumnRules(PaintInfo&, const LayoutPoint&); void paintSelection(PaintInfo&, const LayoutPoint&); - void paintCaret(PaintInfo&, const LayoutPoint&, CaretType); + void paintCarets(PaintInfo&, const LayoutPoint&); - bool hasCaret() const { return hasCaret(CursorCaret) || hasCaret(DragCaret); } - bool hasCaret(CaretType) const; + bool hasCaret() const; - virtual bool avoidsFloats() const; + virtual bool avoidsFloats() const OVERRIDE; bool hitTestColumns(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction); bool hitTestContents(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction); @@ -544,26 +396,23 @@ private: virtual bool isPointInOverflowControl(HitTestResult&, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset); - // FIXME: Make this method const so we can remove the const_cast in computeIntrinsicLogicalWidths. - void computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth); void computeBlockPreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const; // Obtains the nearest enclosing block (including this block) that contributes a first-line style to our inline // children. - virtual RenderBlock* firstLineBlock() const; + virtual RenderBlock* firstLineBlock() const OVERRIDE; - virtual LayoutRect rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const OVERRIDE FINAL; - virtual RenderStyle* outlineStyleForRepaint() const OVERRIDE FINAL; + virtual LayoutRect rectWithOutlineForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, LayoutUnit outlineWidth) const OVERRIDE FINAL; + virtual RenderStyle* outlineStyleForPaintInvalidation() const OVERRIDE FINAL; virtual RenderObject* hoverAncestor() const OVERRIDE FINAL; virtual void updateDragState(bool dragOn) OVERRIDE FINAL; virtual void childBecameNonInline(RenderObject* child) OVERRIDE FINAL; - virtual LayoutRect selectionRectForRepaint(const RenderLayerModelObject* repaintContainer, bool /*clipToVisibleContent*/) OVERRIDE FINAL + virtual LayoutRect selectionRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, bool /*clipToVisibleContent*/) OVERRIDE FINAL { - return selectionGapRectsForRepaint(repaintContainer); + return selectionGapRectsForRepaint(paintInvalidationContainer); } - virtual bool shouldPaintSelectionGaps() const OVERRIDE FINAL; bool isSelectionRoot() const; GapRects selectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* = 0); @@ -571,14 +420,14 @@ private: LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo*); LayoutRect blockSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const PaintInfo*); - LayoutUnit logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position); - LayoutUnit logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position); + virtual LayoutUnit logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position); + virtual LayoutUnit logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position); // FIXME-BLOCKFLOW: Remove virtualizaion when all callers have moved to RenderBlockFlow virtual void clipOutFloatingObjects(RenderBlock*, const PaintInfo*, const LayoutPoint&, const LayoutSize&) { }; - virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const; - virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; + virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const OVERRIDE; + virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const OVERRIDE; LayoutUnit desiredColumnWidth() const; @@ -596,11 +445,9 @@ private: Position positionForBox(InlineBox*, bool start = true) const; PositionWithAffinity positionForPointWithInlineChildren(const LayoutPoint&); - virtual void calcColumnWidth(); + void calcColumnWidth(); void makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlockFlow* newBlockBox, RenderObject* newChild); - bool expandsToEncloseOverhangingFloats() const; - void splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock, RenderBlock* middleBlock, RenderObject* beforeChild, RenderBoxModelObject* oldCont); void splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox, @@ -613,11 +460,6 @@ private: // End helper functions and structs used by layoutBlockChildren. protected: - void determineLogicalLeftPositionForChild(RenderBox* child, ApplyLayoutDeltaMode = DoNotApplyLayoutDelta); - - // Pagination routines. - bool relayoutToAvoidWidows(LayoutStateMaintainer&); - // Returns the logicalOffset at the top of the next page. If the offset passed in is already at the top of the current page, // then nextPageLogicalTop with ExcludePageBoundary will still move to the top of the next page. nextPageLogicalTop with // IncludePageBoundary set will not. @@ -625,9 +467,8 @@ protected: // For a page height of 800px, the first rule will return 800 if the value passed in is 0. The second rule will simply return 0. enum PageBoundaryRule { ExcludePageBoundary, IncludePageBoundary }; LayoutUnit nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule = ExcludePageBoundary) const; - bool hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule = ExcludePageBoundary) const; - virtual ColumnInfo::PaginationUnit paginationUnit() const; + bool createsBlockFormattingContext() const; public: LayoutUnit pageLogicalTopForOffset(LayoutUnit offset) const; @@ -635,8 +476,6 @@ public: LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule = IncludePageBoundary) const; protected: - bool pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const; - // A page break is required at some offset due to space shortage in the current fragmentainer. void setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage); @@ -647,19 +486,11 @@ protected: LayoutUnit adjustForUnsplittableChild(RenderBox* child, LayoutUnit logicalOffset, bool includeMargins = false); // If the child is unsplittable and can't fit on the current page, return the top of the next page/column. void adjustLinePositionForPagination(RootInlineBox*, LayoutUnit& deltaOffset, RenderFlowThread*); // Computes a deltaOffset value that put a line at the top of the next page if it doesn't fit on the current page. - void updateRegionForLine(RootInlineBox*) const; // Adjust from painting offsets to the local coords of this renderer void offsetForContents(LayoutPoint&) const; - // This function is called to test a line box that has moved in the block direction to see if it has ended up in a new - // region/page/column that has a different available line width than the old one. Used to know when you have to dirty a - // line, i.e., that it can't be re-used. - bool lineWidthForPaginatedLineChanged(RootInlineBox*, LayoutUnit lineDelta, RenderFlowThread*) const; - - bool logicalWidthChangedInRegions(RenderFlowThread*) const; - - virtual bool requiresColumns(int desiredColumnCount) const; + bool requiresColumns(int desiredColumnCount) const; virtual bool updateLogicalWidthAndColumnWidth(); @@ -667,8 +498,6 @@ protected: public: virtual LayoutUnit offsetFromLogicalTopOfFirstPage() const OVERRIDE FINAL; - RenderRegion* regionAtBlockOffset(LayoutUnit) const; - RenderRegion* clampToStartAndEndRegions(RenderRegion*) const; public: @@ -687,9 +516,8 @@ public: LayoutUnit m_paginationStrut; LayoutUnit m_pageLogicalOffset; - int m_lineBreakToAvoidWidow; - OwnPtr<ShapeInsideInfo> m_shapeInsideInfo; - bool m_didBreakAtLineToAvoidWidow : 1; + int m_lineBreakToAvoidWidow : 31; + unsigned m_didBreakAtLineToAvoidWidow : 1; }; protected: @@ -698,12 +526,13 @@ 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 : 27; + // WARNING: Don't add any bits here until we are comfortable that removing m_lineHeight has not regressed performance. See http://crrev.com/260073005 for more information. unsigned m_hasMarginBeforeQuirk : 1; // Note these quirk values can't be put in RenderBlockRareData since they are set too frequently. unsigned m_hasMarginAfterQuirk : 1; unsigned m_beingDestroyed : 1; unsigned m_hasMarkupTruncation : 1; unsigned m_hasBorderOrPaddingLogicalWidthChanged : 1; + mutable unsigned m_hasOnlySelfCollapsingChildren : 1; // RenderRubyBase objects need to be able to split and merge, moving their children around // (calling moveChildTo, moveAllChildrenTo, and makeChildrenNonInline). @@ -716,20 +545,6 @@ protected: friend class RenderBlockFlow; }; - -inline bool RenderBlock::allowsShapeInsideInfoSharing(const RenderBlock* other) const -{ - if (!other) - return false; - for (const RenderBlock* current = this; current && current != other && !current->isRenderFlowThread(); current = current->containingBlock()) { - if (current->isInline() || current->isFloating()) - return false; - if (current->parent() != current->containingBlock()) - return false; - } - return true; -} - DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderBlock, isRenderBlock()); } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderBlockFlow.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderBlockFlow.cpp index 96725842afd..0a731d49857 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderBlockFlow.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderBlockFlow.cpp @@ -31,19 +31,19 @@ #include "config.h" #include "core/rendering/RenderBlockFlow.h" +#include "core/accessibility/AXObjectCache.h" #include "core/frame/FrameView.h" +#include "core/rendering/FastTextAutosizer.h" #include "core/rendering/HitTestLocation.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/LayoutRepainter.h" -#include "core/rendering/LineWidth.h" +#include "core/rendering/RenderFlowThread.h" #include "core/rendering/RenderLayer.h" -#include "core/rendering/RenderNamedFlowFragment.h" -#include "core/rendering/RenderNamedFlowThread.h" +#include "core/rendering/RenderMultiColumnFlowThread.h" #include "core/rendering/RenderText.h" #include "core/rendering/RenderView.h" +#include "core/rendering/line/LineWidth.h" #include "core/rendering/svg/SVGTextRunRenderingContext.h" -#include "platform/text/BidiResolver.h" -#include "platform/text/TextRunIterator.h" +#include "platform/text/BidiTextRun.h" using namespace std; @@ -63,6 +63,7 @@ class MarginInfo { bool m_canCollapseWithChildren : 1; bool m_canCollapseMarginBeforeWithChildren : 1; bool m_canCollapseMarginAfterWithChildren : 1; + bool m_canCollapseMarginAfterWithLastChild: 1; // Whether or not we are a quirky container, i.e., do we collapse away top and bottom // margins in our container. Table cells and the body are the common examples. We @@ -120,6 +121,7 @@ public: void setMargin(LayoutUnit p, LayoutUnit n) { ASSERT(!m_discardMargin); m_positiveMargin = p; m_negativeMargin = n; } void setCanCollapseMarginAfterWithChildren(bool collapse) { m_canCollapseMarginAfterWithChildren = collapse; } + void setCanCollapseMarginAfterWithLastChild(bool collapse) { m_canCollapseMarginAfterWithLastChild = collapse; } void setDiscardMargin(bool value) { m_discardMargin = value; } bool atBeforeSideOfBlock() const { return m_atBeforeSideOfBlock; } @@ -127,6 +129,7 @@ public: bool canCollapseWithMarginAfter() const { return m_atAfterSideOfBlock && m_canCollapseMarginAfterWithChildren; } bool canCollapseMarginBeforeWithChildren() const { return m_canCollapseMarginBeforeWithChildren; } bool canCollapseMarginAfterWithChildren() const { return m_canCollapseMarginAfterWithChildren; } + bool canCollapseMarginAfterWithLastChild() const { return m_canCollapseMarginAfterWithLastChild; } bool quirkContainer() const { return m_quirkContainer; } bool determinedMarginBeforeQuirk() const { return m_determinedMarginBeforeQuirk; } bool hasMarginBeforeQuirk() const { return m_hasMarginBeforeQuirk; } @@ -136,7 +139,6 @@ public: bool discardMargin() const { return m_discardMargin; } LayoutUnit margin() const { return m_positiveMargin - m_negativeMargin; } }; - static bool inNormalFlow(RenderBox* child) { RenderBlock* curr = child->containingBlock(); @@ -168,113 +170,187 @@ RenderBlockFlow* RenderBlockFlow::createAnonymous(Document* document) return renderer; } -RenderBlockFlow* RenderBlockFlow::createAnonymousBlockFlow() const +RenderObject* RenderBlockFlow::layoutSpecialExcludedChild(bool relayoutChildren, SubtreeLayoutScope& layoutScope) { - return toRenderBlockFlow(createAnonymousWithParentRendererAndDisplay(this, BLOCK)); + RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread(); + if (!flowThread) + return 0; + setLogicalTopForChild(flowThread, borderBefore() + paddingBefore()); + flowThread->layoutColumns(relayoutChildren, layoutScope); + determineLogicalLeftPositionForChild(flowThread); + return flowThread; } -void RenderBlockFlow::willBeDestroyed() +bool RenderBlockFlow::updateLogicalWidthAndColumnWidth() { - if (lineGridBox()) - lineGridBox()->destroy(); + bool relayoutChildren = RenderBlock::updateLogicalWidthAndColumnWidth(); + if (RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread()) { + if (flowThread->needsNewWidth()) + return true; + } + return relayoutChildren; +} + +void RenderBlockFlow::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight) +{ + if (RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread()) { + LogicalExtentComputedValues computedValues; + computeLogicalHeight(LayoutUnit(), logicalTop(), computedValues); + LayoutUnit columnHeight = computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight(); + pageLogicalHeightChanged = columnHeight != flowThread->columnHeightAvailable(); + flowThread->setColumnHeightAvailable(std::max<LayoutUnit>(columnHeight, 0)); + } else if (hasColumns()) { + ColumnInfo* colInfo = columnInfo(); + + if (!pageLogicalHeight) { + LayoutUnit oldLogicalHeight = logicalHeight(); + setLogicalHeight(0); + // We need to go ahead and set our explicit page height if one exists, so that we can + // avoid doing two layout passes. + updateLogicalHeight(); + LayoutUnit columnHeight = contentLogicalHeight(); + if (columnHeight > 0) { + pageLogicalHeight = columnHeight; + hasSpecifiedPageLogicalHeight = true; + } + setLogicalHeight(oldLogicalHeight); + } + if (colInfo->columnHeight() != pageLogicalHeight && everHadLayout()) { + colInfo->setColumnHeight(pageLogicalHeight); + pageLogicalHeightChanged = true; + } - if (renderNamedFlowFragment()) - setRenderNamedFlowFragment(0); + if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight) + colInfo->clearForcedBreaks(); + } else if (isRenderFlowThread()) { + RenderFlowThread* flowThread = toRenderFlowThread(this); - RenderBlock::willBeDestroyed(); + // FIXME: This is a hack to always make sure we have a page logical height, if said height + // is known. The page logical height thing in LayoutState is meaningless for flow + // thread-based pagination (page height isn't necessarily uniform throughout the flow + // thread), but as long as it is used universally as a means to determine whether page + // height is known or not, we need this. Page height is unknown when column balancing is + // enabled and flow thread height is still unknown (i.e. during the first layout pass). When + // it's unknown, we need to prevent the pagination code from assuming page breaks everywhere + // and thereby eating every top margin. It should be trivial to clean up and get rid of this + // hack once the old multicol implementation is gone. + pageLogicalHeight = flowThread->isPageLogicalHeightKnown() ? LayoutUnit(1) : LayoutUnit(0); + + pageLogicalHeightChanged = flowThread->pageLogicalSizeChanged(); + } } -bool RenderBlockFlow::relayoutForPagination(bool hasSpecifiedPageLogicalHeight, LayoutUnit pageLogicalHeight, LayoutStateMaintainer& statePusher) +bool RenderBlockFlow::shouldRelayoutForPagination(LayoutUnit& pageLogicalHeight, LayoutUnit layoutOverflowLogicalBottom) const { - if (!hasColumns()) - return false; - - OwnPtr<RenderOverflow> savedOverflow = m_overflow.release(); - if (childrenInline()) - addOverflowFromInlineChildren(); - else - addOverflowFromBlockChildren(); - LayoutUnit layoutOverflowLogicalBottom = (isHorizontalWritingMode() ? layoutOverflowRect().maxY() : layoutOverflowRect().maxX()) - borderBefore() - paddingBefore(); - // FIXME: We don't balance properly at all in the presence of forced page breaks. We need to understand what // the distance between forced page breaks is so that we can avoid making the minimum column height too tall. ColumnInfo* colInfo = columnInfo(); - if (!hasSpecifiedPageLogicalHeight) { - LayoutUnit columnHeight = pageLogicalHeight; - int minColumnCount = colInfo->forcedBreaks() + 1; - int desiredColumnCount = colInfo->desiredColumnCount(); - if (minColumnCount >= desiredColumnCount) { - // The forced page breaks are in control of the balancing. Just set the column height to the - // maximum page break distance. - if (!pageLogicalHeight) { - LayoutUnit distanceBetweenBreaks = max<LayoutUnit>(colInfo->maximumDistanceBetweenForcedBreaks(), - view()->layoutState()->pageLogicalOffset(this, borderBefore() + paddingBefore() + layoutOverflowLogicalBottom) - colInfo->forcedBreakOffset()); - columnHeight = max(colInfo->minimumColumnHeight(), distanceBetweenBreaks); - } - } else if (layoutOverflowLogicalBottom > 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)layoutOverflowLogicalBottom / desiredColumnCount)); + LayoutUnit columnHeight = pageLogicalHeight; + const int minColumnCount = colInfo->forcedBreaks() + 1; + const int desiredColumnCount = colInfo->desiredColumnCount(); + if (minColumnCount >= desiredColumnCount) { + // The forced page breaks are in control of the balancing. Just set the column height to the + // maximum page break distance. + if (!pageLogicalHeight) { + LayoutUnit distanceBetweenBreaks = max<LayoutUnit>(colInfo->maximumDistanceBetweenForcedBreaks(), + view()->layoutState()->pageLogicalOffset(*this, borderBefore() + paddingBefore() + layoutOverflowLogicalBottom) - colInfo->forcedBreakOffset()); + columnHeight = max(colInfo->minimumColumnHeight(), distanceBetweenBreaks); } + } else if (layoutOverflowLogicalBottom > boundedMultiply(pageLogicalHeight, desiredColumnCount)) { + // Now that we know the intrinsic height of the columns, we have to rebalance them. + columnHeight = max<LayoutUnit>(colInfo->minimumColumnHeight(), ceilf(layoutOverflowLogicalBottom.toFloat() / desiredColumnCount)); + } - if (columnHeight && columnHeight != pageLogicalHeight) { - statePusher.pop(); - setEverHadLayout(true); - layoutBlock(false, columnHeight); - return true; - } + if (columnHeight && columnHeight != pageLogicalHeight) { + pageLogicalHeight = columnHeight; + return true; } + return false; +} + +void RenderBlockFlow::setColumnCountAndHeight(unsigned count, LayoutUnit pageLogicalHeight) +{ + ColumnInfo* colInfo = columnInfo(); if (pageLogicalHeight) - colInfo->setColumnCountAndHeight(ceilf((float)layoutOverflowLogicalBottom / pageLogicalHeight), pageLogicalHeight); + colInfo->setColumnCountAndHeight(count, pageLogicalHeight); if (columnCount(colInfo)) { setLogicalHeight(borderBefore() + paddingBefore() + colInfo->columnHeight() + borderAfter() + paddingAfter() + scrollbarLogicalHeight()); m_overflow.clear(); - } else { - m_overflow = savedOverflow.release(); } +} - return false; +bool RenderBlockFlow::isSelfCollapsingBlock() const +{ + m_hasOnlySelfCollapsingChildren = RenderBlock::isSelfCollapsingBlock(); + return m_hasOnlySelfCollapsingChildren; } -void RenderBlockFlow::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight) +void RenderBlockFlow::layoutBlock(bool relayoutChildren) { ASSERT(needsLayout()); + ASSERT(isInlineBlockOrInlineTable() || !isInline()); - if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can cause us to come in here. Bail. - return; + // If we are self-collapsing with self-collapsing descendants this will get set to save us burrowing through our + // descendants every time in |isSelfCollapsingBlock|. We reset it here so that |isSelfCollapsingBlock| attempts to burrow + // at least once and so that it always gives a reliable result reflecting the latest layout. + m_hasOnlySelfCollapsingChildren = false; if (!relayoutChildren && simplifiedLayout()) return; - LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); + SubtreeLayoutScope layoutScope(*this); + + // Multiple passes might be required for column and pagination based layout + // In the case of the old column code the number of passes will only be two + // however, in the newer column code the number of passes could equal the + // number of columns. + bool done = false; + LayoutUnit pageLogicalHeight = 0; + LayoutRepainter repainter(*this, checkForPaintInvalidationDuringLayout()); + while (!done) + done = layoutBlockFlow(relayoutChildren, pageLogicalHeight, layoutScope); + + fitBorderToLinesIfNeeded(); + + RenderView* renderView = view(); + if (renderView->layoutState()->pageLogicalHeight()) + setPageLogicalOffset(renderView->layoutState()->pageLogicalOffset(*this, logicalTop())); + + updateLayerTransformAfterLayout(); + + // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if + // we overflow or not. + updateScrollInfoAfterLayout(); + + // Repaint with our new bounds if they are different from our old bounds. + bool didFullRepaint = repainter.repaintAfterLayout(); + if (!didFullRepaint && m_repaintLogicalTop != m_repaintLogicalBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) { + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + setShouldInvalidateOverflowForPaint(true); + else + invalidatePaintForOverflow(); + } + clearNeedsLayout(); +} +inline bool RenderBlockFlow::layoutBlockFlow(bool relayoutChildren, LayoutUnit &pageLogicalHeight, SubtreeLayoutScope& layoutScope) +{ + LayoutUnit oldLeft = logicalLeft(); if (updateLogicalWidthAndColumnWidth()) relayoutChildren = true; rebuildFloatsFromIntruding(); - LayoutUnit previousHeight = logicalHeight(); - // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(), - // for consistency with other render classes? - setLogicalHeight(0); - bool pageLogicalHeightChanged = false; bool hasSpecifiedPageLogicalHeight = false; checkForPaginationLogicalHeightChange(pageLogicalHeight, pageLogicalHeightChanged, hasSpecifiedPageLogicalHeight); - - RenderView* renderView = view(); - LayoutStateMaintainer statePusher(renderView, this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged, columnInfo()); - - // Regions changing widths can force us to relayout our children. - RenderFlowThread* flowThread = flowThreadContainingBlock(); - if (logicalWidthChangedInRegions(flowThread)) - relayoutChildren = true; - if (updateRegionsAndShapesLogicalSize(flowThread)) - relayoutChildren = true; - if (!relayoutChildren && isRenderNamedFlowFragmentContainer()) + if (pageLogicalHeightChanged) relayoutChildren = true; + LayoutState state(*this, locationOffset(), pageLogicalHeight, pageLogicalHeightChanged, columnInfo()); + // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track // our current maximal positive and negative margins. These values are used when we // are collapsed with adjacent blocks, so for example, if you have block A and B @@ -285,62 +361,75 @@ void RenderBlockFlow::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalH // // Start out by setting our margin values to our current margins. Table cells have // no margins, so we don't fill in the values for table cells. - bool isCell = isTableCell(); - if (!isCell) { + if (!isTableCell()) { initMaxMarginValues(); - setHasMarginBeforeQuirk(style()->hasMarginBeforeQuirk()); setHasMarginAfterQuirk(style()->hasMarginAfterQuirk()); setPaginationStrut(0); } - SubtreeLayoutScope layoutScope(this); + LayoutUnit beforeEdge = borderBefore() + paddingBefore(); + LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight(); + LayoutUnit previousHeight = logicalHeight(); + setLogicalHeight(beforeEdge); m_repaintLogicalTop = 0; m_repaintLogicalBottom = 0; - LayoutUnit maxFloatLogicalBottom = 0; if (!firstChild() && !isAnonymousBlock()) setChildrenInline(true); + + FastTextAutosizer::LayoutScope fastTextAutosizerLayoutScope(this); + if (childrenInline()) - layoutInlineChildren(relayoutChildren, m_repaintLogicalTop, m_repaintLogicalBottom); + layoutInlineChildren(relayoutChildren, m_repaintLogicalTop, m_repaintLogicalBottom, afterEdge); else - layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom, layoutScope); - - if (frameView()->partialLayout().isStopping()) { - statePusher.pop(); - return; - } + layoutBlockChildren(relayoutChildren, layoutScope, beforeEdge, afterEdge); // Expand our intrinsic height to encompass floats. - LayoutUnit toAdd = borderAfter() + paddingAfter() + scrollbarLogicalHeight(); - if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats()) - setLogicalHeight(lowestFloatLogicalBottom() + toAdd); + if (lowestFloatLogicalBottom() > (logicalHeight() - afterEdge) && createsBlockFormattingContext()) + setLogicalHeight(lowestFloatLogicalBottom() + afterEdge); - if (relayoutForPagination(hasSpecifiedPageLogicalHeight, pageLogicalHeight, statePusher) || relayoutToAvoidWidows(statePusher)) { - ASSERT(!shouldBreakAtLineToAvoidWidow()); - return; + if (RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread()) { + if (flowThread->recalculateColumnHeights()) { + setChildNeedsLayout(MarkOnlyThis); + return false; + } + } else if (hasColumns()) { + OwnPtr<RenderOverflow> savedOverflow = m_overflow.release(); + if (childrenInline()) + addOverflowFromInlineChildren(); + else + addOverflowFromBlockChildren(); + LayoutUnit layoutOverflowLogicalBottom = (isHorizontalWritingMode() ? layoutOverflowRect().maxY() : layoutOverflowRect().maxX()) - borderBefore() - paddingBefore(); + m_overflow = savedOverflow.release(); + + if (!hasSpecifiedPageLogicalHeight && shouldRelayoutForPagination(pageLogicalHeight, layoutOverflowLogicalBottom)) { + setEverHadLayout(true); + return false; + } + + setColumnCountAndHeight(ceilf(layoutOverflowLogicalBottom.toFloat() / pageLogicalHeight.toFloat()), pageLogicalHeight.toFloat()); + } + + if (shouldBreakAtLineToAvoidWidow()) { + setEverHadLayout(true); + return false; } // Calculate our new height. LayoutUnit oldHeight = logicalHeight(); LayoutUnit oldClientAfterEdge = clientLogicalBottom(); - // Before updating the final size of the flow thread make sure a forced break is applied after the content. - // This ensures the size information is correctly computed for the last auto-height region receiving content. - if (isRenderFlowThread()) - toRenderFlowThread(this)->applyBreakAfterContent(oldClientAfterEdge); - updateLogicalHeight(); LayoutUnit newHeight = logicalHeight(); - if (oldHeight != newHeight) { - if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) { - // One of our children's floats may have become an overhanging float for us. We need to look for it. - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (child->isRenderBlockFlow() && !child->isFloatingOrOutOfFlowPositioned()) { - RenderBlockFlow* block = toRenderBlockFlow(child); - if (block->lowestFloatLogicalBottom() + block->logicalTop() > newHeight) - addOverhangingFloats(block, false); - } + if (oldHeight > newHeight && !childrenInline()) { + // One of our children's floats may have become an overhanging float for us. + for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { + if (child->isRenderBlockFlow() && !child->isFloatingOrOutOfFlowPositioned()) { + RenderBlockFlow* block = toRenderBlockFlow(child); + if (block->lowestFloatLogicalBottom() + block->logicalTop() <= newHeight) + break; + addOverhangingFloats(block, false); } } } @@ -349,42 +438,62 @@ void RenderBlockFlow::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalH if (heightChanged) relayoutChildren = true; - layoutPositionedObjects(relayoutChildren || isRoot()); + layoutPositionedObjects(relayoutChildren || isDocumentElement(), oldLeft != logicalLeft() ? ForcedLayoutAfterContainingBlockMoved : DefaultLayout); - updateRegionsAndShapesAfterChildLayout(flowThread, heightChanged); + computeRegionRangeForBlock(flowThreadContainingBlock()); // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway). computeOverflow(oldClientAfterEdge); - statePusher.pop(); - - fitBorderToLinesIfNeeded(); + return true; +} - if (frameView()->partialLayout().isStopping()) - return; +void RenderBlockFlow::determineLogicalLeftPositionForChild(RenderBox* child, ApplyLayoutDeltaMode applyDelta) +{ + LayoutUnit startPosition = borderStart() + paddingStart(); + if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) + startPosition -= verticalScrollbarWidth(); + LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth(); - if (renderView->layoutState()->m_pageLogicalHeight) - setPageLogicalOffset(renderView->layoutState()->pageLogicalOffset(this, logicalTop())); + // Add in our start margin. + LayoutUnit childMarginStart = marginStartForChild(child); + LayoutUnit newPosition = startPosition + childMarginStart; - updateLayerTransform(); + // 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() && !flowThreadContainingBlock()) + newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child)); - // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if - // we overflow or not. - updateScrollInfoAfterLayout(); + setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta); +} - // Repaint with our new bounds if they are different from our old bounds. - bool didFullRepaint = repainter.repaintAfterLayout(); - if (!didFullRepaint && m_repaintLogicalTop != m_repaintLogicalBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) { - if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) - setShouldRepaintOverflowIfNeeded(true); - else - repaintOverflow(); +void RenderBlockFlow::setLogicalLeftForChild(RenderBox* child, LayoutUnit logicalLeft, ApplyLayoutDeltaMode applyDelta) +{ + if (isHorizontalWritingMode()) { + if (applyDelta == ApplyLayoutDelta && !RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + view()->addLayoutDelta(LayoutSize(child->x() - logicalLeft, 0)); + child->setX(logicalLeft); + } else { + if (applyDelta == ApplyLayoutDelta && !RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + view()->addLayoutDelta(LayoutSize(0, child->y() - logicalLeft)); + child->setY(logicalLeft); } +} - clearNeedsLayout(); +void RenderBlockFlow::setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop, ApplyLayoutDeltaMode applyDelta) +{ + if (isHorizontalWritingMode()) { + if (applyDelta == ApplyLayoutDelta && !RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + view()->addLayoutDelta(LayoutSize(0, child->y() - logicalTop)); + child->setY(logicalTop); + } else { + if (applyDelta == ApplyLayoutDelta && !RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + view()->addLayoutDelta(LayoutSize(child->x() - logicalTop, 0)); + child->setX(logicalTop); + } } -void RenderBlockFlow::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom) +void RenderBlockFlow::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom) { LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore(); LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore(); @@ -402,8 +511,8 @@ void RenderBlockFlow::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, LayoutRect oldRect = child->frameRect(); LayoutUnit oldLogicalTop = logicalTopForChild(child); -#if !ASSERT_DISABLED - LayoutSize oldLayoutDelta = view()->layoutDelta(); +#if ASSERT_ENABLED + LayoutSize oldLayoutDelta = RuntimeEnabledFeatures::repaintAfterLayoutEnabled() ? LayoutSize() : view()->layoutDelta(); #endif // Go ahead and position the child as though it didn't collapse with the top. setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta); @@ -434,7 +543,7 @@ void RenderBlockFlow::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlockFlow->lowestFloatLogicalBottom()); } - SubtreeLayoutScope layoutScope(child); + SubtreeLayoutScope layoutScope(*child); if (!child->needsLayout()) child->markForPaginationRelayoutIfNeeded(layoutScope); @@ -443,18 +552,16 @@ void RenderBlockFlow::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, if (childNeededLayout) child->layout(); - if (frameView()->partialLayout().isStopping()) - return; - // Cache if we are at the top of the block right now. bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock(); + bool childIsSelfCollapsing = child->isSelfCollapsingBlock(); // Now determine the correct ypos based off examination of collapsing margin // values. - LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo); + LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo, childIsSelfCollapsing); // Now check for clear. - LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear); + LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear, childIsSelfCollapsing); bool paginated = view()->layoutState()->isPaginated(); if (paginated) { @@ -468,7 +575,7 @@ void RenderBlockFlow::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens // when collapseMargins dynamically adds overhanging floats because of a child with negative margins. if (logicalTopAfterClear != logicalTopEstimate || child->needsLayout() || (paginated && childRenderBlock && childRenderBlock->shouldBreakAtLineToAvoidWidow())) { - SubtreeLayoutScope layoutScope(child); + SubtreeLayoutScope layoutScope(*child); if (child->shrinkToAvoidFloats()) { // The child's width depends on the line width. // When the child shifts to clear an item, its width can @@ -488,16 +595,22 @@ void RenderBlockFlow::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, child->layoutIfNeeded(); } + // If we previously encountered a self-collapsing sibling of this child that had clearance then + // we set this bit to ensure we would not collapse the child's margins, and those of any subsequent + // self-collapsing siblings, with our parent. If this child is not self-collapsing then it can + // collapse its margins with the parent so reset the bit. + if (!marginInfo.canCollapseMarginAfterWithLastChild() && !childIsSelfCollapsing) + marginInfo.setCanCollapseMarginAfterWithLastChild(true); + // We are no longer at the top of the block if we encounter a non-empty child. // This has to be done after checking for clear, so that margins can be reset if a clear occurred. - if (marginInfo.atBeforeSideOfBlock() && !child->isSelfCollapsingBlock()) + if (marginInfo.atBeforeSideOfBlock() && !childIsSelfCollapsing) marginInfo.setAtBeforeSideOfBlock(false); // Now place the child in the correct left position determineLogicalLeftPositionForChild(child, ApplyLayoutDelta); LayoutSize childOffset = child->location() - oldRect.location(); - relayoutShapeDescendantIfMoved(childRenderBlock, childOffset); // Update our height now that the child has been placed in the correct position. setLogicalHeight(logicalHeight() + logicalHeightForChild(child)); @@ -507,24 +620,25 @@ void RenderBlockFlow::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, } // If the child has overhanging floats that intrude into following siblings (or possibly out // of this block), then the parent gets notified of the floats now. - if (childRenderBlockFlow && childRenderBlockFlow->containsFloats()) - maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(childRenderBlockFlow, !childNeededLayout)); + if (childRenderBlockFlow) + addOverhangingFloats(childRenderBlockFlow, !childNeededLayout); if (childOffset.width() || childOffset.height()) { - view()->addLayoutDelta(childOffset); + if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + view()->addLayoutDelta(childOffset); // If the child moved, we have to repaint it as well as any floating/positioned // descendants. An exception is if we need a layout. In this case, we know we're going to // repaint ourselves (and the child) anyway. if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && childHadLayout && !selfNeedsLayout()) child->repaintOverhangingFloats(true); - else if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout()) + else if (childHadLayout && !selfNeedsLayout() && child->checkForPaintInvalidationDuringLayout()) child->repaintDuringLayoutIfMoved(oldRect); } - if (!childHadLayout && child->checkForRepaintDuringLayout()) { + if (!childHadLayout && child->checkForPaintInvalidation()) { if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) - child->repaint(); + child->paintInvalidationForWholeRenderer(); child->repaintOverhangingFloats(true); } @@ -535,7 +649,9 @@ void RenderBlockFlow::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, setLogicalHeight(newHeight); } - ASSERT(view()->layoutDeltaMatches(oldLayoutDelta)); + if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) { + ASSERT(view()->layoutDeltaMatches(oldLayoutDelta)); + } } LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox* child, bool atBeforeSideOfBlock) @@ -556,7 +672,7 @@ LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopA child->setChildNeedsLayout(MarkOnlyThis); } - SubtreeLayoutScope layoutScope(child); + SubtreeLayoutScope layoutScope(*child); if (childRenderBlock) { if (!child->avoidsFloats() && childRenderBlock->containsFloats()) @@ -574,31 +690,19 @@ LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopA // If the object has a page or column break value of "before", then we should shift to the top of the next page. LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear); - if (pageLogicalHeightForOffset(result)) { - LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary); - LayoutUnit spaceShortage = child->logicalHeight() - remainingLogicalHeight; - if (spaceShortage > 0) { - // If the child crosses a column boundary, report a break, in case nothing inside it has already - // done so. The column balancer needs to know how much it has to stretch the columns to make more - // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME: - // This should be improved, though, because here we just pretend that the child is - // unsplittable. A splittable child, on the other hand, has break opportunities at every position - // where there's no child content, border or padding. In other words, we risk stretching more - // than necessary. - setPageBreak(result, spaceShortage); - } - } - // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one. LayoutUnit logicalTopBeforeUnsplittableAdjustment = result; LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result); LayoutUnit paginationStrut = 0; LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment; - if (unsplittableAdjustmentDelta) + LayoutUnit childLogicalHeight = child->logicalHeight(); + if (unsplittableAdjustmentDelta) { + setPageBreak(result, childLogicalHeight - unsplittableAdjustmentDelta); paginationStrut = unsplittableAdjustmentDelta; - else if (childRenderBlock && childRenderBlock->paginationStrut()) + } else if (childRenderBlock && childRenderBlock->paginationStrut()) { paginationStrut = childRenderBlock->paginationStrut(); + } if (paginationStrut) { // We are willing to propagate out to our parent block as long as we were at the top of the block prior @@ -615,6 +719,27 @@ LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopA } } + if (!unsplittableAdjustmentDelta) { + if (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(result)) { + LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary); + LayoutUnit spaceShortage = childLogicalHeight - remainingLogicalHeight; + if (spaceShortage > 0) { + // If the child crosses a column boundary, report a break, in case nothing inside it + // has already done so. The column balancer needs to know how much it has to stretch + // the columns to make more content fit. If no breaks are reported (but do occur), + // the balancer will have no clue. Only measure the space after the last column + // boundary, in case it crosses more than one. + LayoutUnit spaceShortageInLastColumn = intMod(spaceShortage, pageLogicalHeight); + setPageBreak(result, spaceShortageInLastColumn ? spaceShortageInLastColumn : spaceShortage); + } else if (remainingLogicalHeight == pageLogicalHeight && offsetFromLogicalTopOfFirstPage() + child->logicalTop()) { + // We're at the very top of a page or column, and it's not the first one. This child + // may turn out to be the smallest piece of content that causes a page break, so we + // need to report it. + setPageBreak(result, childLogicalHeight); + } + } + } + // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child. setLogicalHeight(logicalHeight() + (result - oldTop)); @@ -632,14 +757,14 @@ void RenderBlockFlow::rebuildFloatsFromIntruding() const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); FloatingObjectSetIterator end = floatingObjectSet.end(); for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); if (!floatingObject->isDescendant()) oldIntrudingFloatSet.add(floatingObject->renderer()); } } // Inline blocks are covered by the isReplaced() check in the avoidFloats method. - if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) { + if (avoidsFloats() || isDocumentElement() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) { if (m_floatingObjects) { m_floatingObjects->clear(); } @@ -663,13 +788,13 @@ void RenderBlockFlow::rebuildFloatsFromIntruding() if (!parent() || !parent()->isRenderBlockFlow()) return; - // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are - // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted - // to avoid floats. + // Attempt to locate a previous sibling with overhanging floats. We skip any elements that + // may have shifted to avoid floats, and any objects whose floats cannot interact with objects + // outside it (i.e. objects that create a new block formatting context). RenderBlockFlow* parentBlockFlow = toRenderBlockFlow(parent()); bool parentHasFloats = false; RenderObject* prev = previousSibling(); - while (prev && (prev->isFloatingOrOutOfFlowPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) { + while (prev && (!prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats() || toRenderBlock(prev)->createsBlockFormattingContext())) { if (prev->isFloating()) parentHasFloats = true; prev = prev->previousSibling(); @@ -678,22 +803,18 @@ void RenderBlockFlow::rebuildFloatsFromIntruding() // First add in floats from the parent. Self-collapsing blocks let their parent track any floats that intrude into // them (as opposed to floats they contain themselves) so check for those here too. LayoutUnit logicalTopOffset = logicalTop(); - if (parentHasFloats || (prev && toRenderBlockFlow(prev)->isSelfCollapsingBlock() && parentBlockFlow->lowestFloatLogicalBottom() > logicalTopOffset)) + bool parentHasIntrudingFloats = !parentHasFloats && (!prev || toRenderBlockFlow(prev)->isSelfCollapsingBlock()) && parentBlockFlow->lowestFloatLogicalBottom() > logicalTopOffset; + if (parentHasFloats || parentHasIntrudingFloats) addIntrudingFloats(parentBlockFlow, parentBlockFlow->logicalLeftOffsetForContent(), logicalTopOffset); - LayoutUnit logicalLeftOffset = 0; + // Add overhanging floats from the previous RenderBlockFlow, but only if it has a float that intrudes into our space. if (prev) { - logicalTopOffset -= toRenderBox(prev)->logicalTop(); - } else { - prev = parentBlockFlow; - logicalLeftOffset += parentBlockFlow->logicalLeftOffsetForContent(); + RenderBlockFlow* blockFlow = toRenderBlockFlow(prev); + logicalTopOffset -= blockFlow->logicalTop(); + if (blockFlow->lowestFloatLogicalBottom() > logicalTopOffset) + addIntrudingFloats(blockFlow, 0, logicalTopOffset); } - // Add overhanging floats from the previous RenderBlockFlow, but only if it has a float that intrudes into our space. - RenderBlockFlow* blockFlow = toRenderBlockFlow(prev); - if (blockFlow->m_floatingObjects && blockFlow->lowestFloatLogicalBottom() > logicalTopOffset) - addIntrudingFloats(blockFlow, logicalLeftOffset, logicalTopOffset); - if (childrenInline()) { LayoutUnit changeLogicalTop = LayoutUnit::max(); LayoutUnit changeLogicalBottom = LayoutUnit::min(); @@ -701,7 +822,7 @@ void RenderBlockFlow::rebuildFloatsFromIntruding() const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); FloatingObjectSetIterator end = floatingObjectSet.end(); for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); FloatingObject* oldFloatingObject = floatMap.get(floatingObject->renderer()); LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject); if (oldFloatingObject) { @@ -722,12 +843,12 @@ void RenderBlockFlow::rebuildFloatsFromIntruding() } } - floatMap.remove(floatingObject->renderer()); if (oldFloatingObject->originatingLine() && !selfNeedsLayout()) { ASSERT(oldFloatingObject->originatingLine()->renderer() == this); oldFloatingObject->originatingLine()->markDirty(); } - delete oldFloatingObject; + + floatMap.remove(floatingObject->renderer()); } else { changeLogicalTop = 0; changeLogicalBottom = max(changeLogicalBottom, logicalBottom); @@ -737,13 +858,12 @@ void RenderBlockFlow::rebuildFloatsFromIntruding() RendererToFloatInfoMap::iterator end = floatMap.end(); for (RendererToFloatInfoMap::iterator it = floatMap.begin(); it != end; ++it) { - FloatingObject* floatingObject = (*it).value; + OwnPtr<FloatingObject>& floatingObject = it->value; if (!floatingObject->isDescendant()) { changeLogicalTop = 0; - changeLogicalBottom = max(changeLogicalBottom, logicalBottomForFloat(floatingObject)); + changeLogicalBottom = max(changeLogicalBottom, logicalBottomForFloat(floatingObject.get())); } } - deleteAllValues(floatMap); markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom); } else if (!oldIntrudingFloatSet.isEmpty()) { @@ -762,19 +882,10 @@ void RenderBlockFlow::rebuildFloatsFromIntruding() } } -void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom, SubtreeLayoutScope& layoutScope) +void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, SubtreeLayoutScope& layoutScope, LayoutUnit beforeEdge, LayoutUnit afterEdge) { dirtyForLayoutFromPercentageHeightDescendants(layoutScope); - LayoutUnit beforeEdge = borderBefore() + paddingBefore(); - LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight(); - - setLogicalHeight(beforeEdge); - - // Lay out our hypothetical grid line as though it occurs at the top of the block. - if (view()->layoutState()->lineGrid() == this) - layoutLineGridBox(); - // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts, MarginInfo marginInfo(this, beforeEdge, afterEdge); @@ -784,15 +895,16 @@ void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& max RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren, layoutScope); LayoutUnit previousFloatLogicalBottom = 0; - maxFloatLogicalBottom = 0; RenderBox* next = firstChildBox(); + RenderBox* lastNormalFlowChild = 0; while (next) { RenderBox* child = next; next = child->nextSiblingBox(); - LayoutRectRecorder recorder(*child); + // FIXME: this should only be set from clearNeedsLayout crbug.com/361250 + child->setLayoutDidGetCalled(true); if (childToExclude == child) continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs). @@ -811,21 +923,19 @@ void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& max } // Lay out the child. - layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom); - - // If doing a partial layout and the child was the target renderer, early exit here. - if (frameView()->partialLayout().checkPartialLayoutComplete(child)) - break; + layoutBlockChild(child, marginInfo, previousFloatLogicalBottom); + lastNormalFlowChild = child; } // Now do the handling of the bottom of the block, adding in our bottom border/padding and // determining the correct collapsed bottom margin information. - handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo); + handleAfterSideOfBlock(lastNormalFlowChild, beforeEdge, afterEdge, marginInfo); } // Our MarginInfo state used when laying out block children. MarginInfo::MarginInfo(RenderBlockFlow* blockFlow, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding) - : m_atBeforeSideOfBlock(true) + : m_canCollapseMarginAfterWithLastChild(true) + , m_atBeforeSideOfBlock(true) , m_atAfterSideOfBlock(false) , m_hasMarginBeforeQuirk(false) , m_hasMarginAfterQuirk(false) @@ -834,10 +944,7 @@ MarginInfo::MarginInfo(RenderBlockFlow* blockFlow, LayoutUnit beforeBorderPaddin { RenderStyle* blockStyle = blockFlow->style(); ASSERT(blockFlow->isRenderView() || blockFlow->parent()); - m_canCollapseWithChildren = !blockFlow->isRenderView() && !blockFlow->isRoot() && !blockFlow->isOutOfFlowPositioned() - && !blockFlow->isFloating() && !blockFlow->isTableCell() && !blockFlow->hasOverflowClip() && !blockFlow->isInlineBlockOrInlineTable() - && !blockFlow->isRenderFlowThread() && !blockFlow->isWritingModeRoot() && !blockFlow->parent()->isFlexibleBox() - && blockStyle->hasAutoColumnCount() && blockStyle->hasAutoColumnWidth() && !blockStyle->columnSpan(); + m_canCollapseWithChildren = !blockFlow->createsBlockFormattingContext() && !blockFlow->isRenderFlowThread() && !blockFlow->isRenderView(); m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle->marginBeforeCollapse() != MSEPARATE; @@ -916,11 +1023,10 @@ RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox* c return RenderBlockFlow::MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative); } -LayoutUnit RenderBlockFlow::collapseMargins(RenderBox* child, MarginInfo& marginInfo) +LayoutUnit RenderBlockFlow::collapseMargins(RenderBox* child, MarginInfo& marginInfo, bool childIsSelfCollapsing) { bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child); bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child); - bool childIsSelfCollapsing = child->isSelfCollapsingBlock(); // The child discards the before margin when the the after margin has discard in the case of a self collapsing block. childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing); @@ -988,11 +1094,12 @@ LayoutUnit RenderBlockFlow::collapseMargins(RenderBox* child, MarginInfo& margin LayoutUnit clearanceForSelfCollapsingBlock; RenderObject* prev = child->previousSibling(); + RenderBlockFlow* previousBlockFlow = prev && prev->isRenderBlockFlow() && !prev->isFloatingOrOutOfFlowPositioned() ? toRenderBlockFlow(prev) : 0; // If the child's previous sibling is a self-collapsing block that cleared a float then its top border edge has been set at the bottom border edge // of the float. Since we want to collapse the child's top margin with the self-collapsing block's top and bottom margins we need to adjust our parent's height to match the // margin top of the self-collapsing block. If the resulting collapsed margin leaves the child still intruding into the float then we will want to clear it. - if (!marginInfo.canCollapseWithMarginBefore() && prev && prev->isRenderBlockFlow() && toRenderBlockFlow(prev)->isSelfCollapsingBlock()) { - clearanceForSelfCollapsingBlock = toRenderBlockFlow(prev)->marginOffsetForSelfCollapsingBlock(); + if (!marginInfo.canCollapseWithMarginBefore() && previousBlockFlow && previousBlockFlow->isSelfCollapsingBlock()) { + clearanceForSelfCollapsingBlock = previousBlockFlow->marginOffsetForSelfCollapsingBlock(); setLogicalHeight(logicalHeight() - clearanceForSelfCollapsingBlock); } @@ -1054,21 +1161,19 @@ LayoutUnit RenderBlockFlow::collapseMargins(RenderBox* child, MarginInfo& margin // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins // collapsed into the page edge. LayoutState* layoutState = view()->layoutState(); - if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop - && hasNextPage(beforeCollapseLogicalTop)) { + if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop) { LayoutUnit oldLogicalTop = logicalTop; logicalTop = min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop)); setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop)); } - if (prev && prev->isRenderBlockFlow() && !prev->isFloatingOrOutOfFlowPositioned()) { + if (previousBlockFlow) { // If |child| is a self-collapsing block it may have collapsed into a previous sibling and although it hasn't reduced the height of the parent yet // any floats from the parent will now overhang. - RenderBlockFlow* blockFlow = toRenderBlockFlow(prev); LayoutUnit oldLogicalHeight = logicalHeight(); setLogicalHeight(logicalTop); - if (blockFlow->containsFloats() && !blockFlow->avoidsFloats() && (blockFlow->logicalTop() + blockFlow->lowestFloatLogicalBottom()) > logicalTop) - addOverhangingFloats(blockFlow, false); + if (!previousBlockFlow->avoidsFloats() && (previousBlockFlow->logicalTop() + previousBlockFlow->lowestFloatLogicalBottom()) > logicalTop) + addOverhangingFloats(previousBlockFlow, false); setLogicalHeight(oldLogicalHeight); // If |child|'s previous sibling is a self-collapsing block that cleared a float and margin collapsing resulted in |child| moving up @@ -1076,7 +1181,7 @@ LayoutUnit RenderBlockFlow::collapseMargins(RenderBox* child, MarginInfo& margin // floats in the parent that overhang |child|'s new logical top. bool logicalTopIntrudesIntoFloat = clearanceForSelfCollapsingBlock > 0 && logicalTop < beforeCollapseLogicalTop; if (logicalTopIntrudesIntoFloat && containsFloats() && !child->avoidsFloats() && lowestFloatLogicalBottom() > logicalTop) - child->setNeedsLayout(); + child->setNeedsLayoutAndFullPaintInvalidation(); } return logicalTop; @@ -1106,13 +1211,35 @@ void RenderBlockFlow::adjustPositionedBlock(RenderBox* child, const MarginInfo& } } -LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos) +LayoutUnit RenderBlockFlow::computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart) +{ + LayoutUnit startPosition = startOffsetForContent(); + + // Add in our start margin. + LayoutUnit oldPosition = startPosition + childMarginStart; + LayoutUnit newPosition = oldPosition; + + LayoutUnit blockOffset = logicalTopForChild(child); + LayoutUnit startOff = startOffsetForLine(blockOffset, false, logicalHeightForChild(child)); + + if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) { + 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) { + newPosition = startOff + childMarginStart; + } + + return newPosition - oldPosition; +} + +LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos, bool childIsSelfCollapsing) { LayoutUnit heightIncrease = getClearDelta(child, yPos); if (!heightIncrease) return yPos; - if (child->isSelfCollapsingBlock()) { + if (childIsSelfCollapsing) { bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child); // For self-collapsing blocks that clear, they can still collapse their @@ -1131,15 +1258,9 @@ LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox* child, MarginInfo& ma // CSS2.1 states: // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block." - // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings - // for a block with height - if none is found then don't allow the margins to collapse with the parent. - bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren(); - for (RenderBox* curr = child->nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) { - if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock()) - wouldCollapseMarginsWithParent = false; - } - if (wouldCollapseMarginsWithParent) - marginInfo.setCanCollapseMarginAfterWithChildren(false); + // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Set a bit to ensure + // this happens; it will get reset if we encounter an in-flow sibling that is not self-collapsing. + marginInfo.setCanCollapseMarginAfterWithLastChild(false); // For now set the border-top of |child| flush with the bottom border-edge of the float so it can layout any floating or positioned children of // its own at the correct vertical position. If subsequent siblings attempt to collapse with |child|'s margins in |collapseMargins| we will @@ -1157,9 +1278,6 @@ LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox* child, MarginInfo& ma if (marginInfo.canCollapseWithMarginBefore()) { // We can no longer collapse with the top of the block since a clear // occurred. The empty blocks collapse into the cleared block. - // FIXME: This isn't quite correct. Need clarification for what to do - // if the height the cleared block is offset by is smaller than the - // margins involved. setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin); marginInfo.setAtBeforeSideOfBlock(false); @@ -1201,7 +1319,7 @@ void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky. // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing. // FIXME: Use writing mode independent accessor for marginBeforeCollapse. - if ((document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child->style()->marginBeforeCollapse() == MSEPARATE) + if ((document().inQuirksMode() && hasMarginBeforeQuirk(child) && (isTableCell() || isBody())) || child->style()->marginBeforeCollapse() == MSEPARATE) return; // The margins are discarded by a child that specified -webkit-margin-collapse: discard. @@ -1281,8 +1399,7 @@ LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox* child, const M // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current // page. LayoutState* layoutState = view()->layoutState(); - if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight() - && hasNextPage(logicalHeight())) + if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()) logicalTopEstimate = min(logicalTopEstimate, nextPageLogicalTop(logicalHeight())); logicalTopEstimate += getClearDelta(child, logicalTopEstimate); @@ -1333,16 +1450,18 @@ void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo) setLogicalHeight(logicalHeight() - marginOffset); } -void RenderBlockFlow::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo) +void RenderBlockFlow::handleAfterSideOfBlock(RenderBox* lastChild, LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo) { marginInfo.setAtAfterSideOfBlock(true); // If our last child was a self-collapsing block with clearance then our logical height is flush with the // bottom edge of the float that the child clears. The correct vertical position for the margin-collapsing we want // to perform now is at the child's margin-top - so adjust our height to that position. - RenderObject* child = lastChild(); - if (child && child->isRenderBlockFlow() && toRenderBlockFlow(child)->isSelfCollapsingBlock()) - setLogicalHeight(logicalHeight() - toRenderBlockFlow(child)->marginOffsetForSelfCollapsingBlock()); + if (lastChild && lastChild->isRenderBlockFlow() && lastChild->isSelfCollapsingBlock()) + setLogicalHeight(logicalHeight() - toRenderBlockFlow(lastChild)->marginOffsetForSelfCollapsingBlock()); + + if (marginInfo.canCollapseMarginAfterWithChildren() && !marginInfo.canCollapseMarginAfterWithLastChild()) + marginInfo.setCanCollapseMarginAfterWithChildren(false); // If we can't collapse with children then go ahead and add in the bottom margin. if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore() @@ -1478,19 +1597,21 @@ bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox* child) co LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox* child, LayoutUnit logicalOffset) { // FIXME: Add page break checking here when we support printing. - bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns(); - bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this. RenderFlowThread* flowThread = flowThreadContainingBlock(); - bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread(); - bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS) - || (checkRegionBreaks && child->style()->regionBreakBefore() == PBALWAYS); - if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) { - if (checkColumnBreaks) - view()->layoutState()->addForcedColumnBreak(child, logicalOffset); - if (checkRegionBreaks) { - LayoutUnit offsetBreakAdjustment = 0; - if (flowThread->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset, child, true, &offsetBreakAdjustment)) - return logicalOffset + offsetBreakAdjustment; + bool isInsideMulticolFlowThread = flowThread; + bool checkColumnBreaks = isInsideMulticolFlowThread || view()->layoutState()->isPaginatingColumns(); + bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->pageLogicalHeight(); // FIXME: Once columns can print we have to check this. + bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) + || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS); + if (checkBeforeAlways && inNormalFlow(child)) { + if (checkColumnBreaks) { + if (isInsideMulticolFlowThread) { + LayoutUnit offsetBreakAdjustment = 0; + if (flowThread->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset, child, true, &offsetBreakAdjustment)) + return logicalOffset + offsetBreakAdjustment; + } else { + view()->layoutState()->addForcedColumnBreak(*child, logicalOffset); + } } return nextPageLogicalTop(logicalOffset, IncludePageBoundary); } @@ -1500,24 +1621,26 @@ LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox* child, LayoutUnit logica LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox* child, LayoutUnit logicalOffset, MarginInfo& marginInfo) { // FIXME: Add page break checking here when we support printing. - bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns(); - bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this. RenderFlowThread* flowThread = flowThreadContainingBlock(); - bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread(); - bool checkAfterAlways = (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS) - || (checkRegionBreaks && child->style()->regionBreakAfter() == PBALWAYS); - if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) { + bool isInsideMulticolFlowThread = flowThread; + bool checkColumnBreaks = isInsideMulticolFlowThread || view()->layoutState()->isPaginatingColumns(); + bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->pageLogicalHeight(); // FIXME: Once columns can print we have to check this. + bool checkAfterAlways = (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS) + || (checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS); + if (checkAfterAlways && inNormalFlow(child)) { LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin(); // So our margin doesn't participate in the next collapsing steps. marginInfo.clearMargin(); - if (checkColumnBreaks) - view()->layoutState()->addForcedColumnBreak(child, logicalOffset); - if (checkRegionBreaks) { - LayoutUnit offsetBreakAdjustment = 0; - if (flowThread->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, child, false, &offsetBreakAdjustment)) - return logicalOffset + marginOffset + offsetBreakAdjustment; + if (checkColumnBreaks) { + if (isInsideMulticolFlowThread) { + LayoutUnit offsetBreakAdjustment = 0; + if (flowThread->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, child, false, &offsetBreakAdjustment)) + return logicalOffset + marginOffset + offsetBreakAdjustment; + } else { + view()->layoutState()->addForcedColumnBreak(*child, logicalOffset); + } } return nextPageLogicalTop(logicalOffset, IncludePageBoundary); } @@ -1532,7 +1655,7 @@ void RenderBlockFlow::addOverflowFromFloats() const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); FloatingObjectSetIterator end = floatingObjectSet.end(); for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); if (floatingObject->isDescendant()) addOverflowFromChild(floatingObject->renderer(), IntSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject))); } @@ -1541,10 +1664,23 @@ void RenderBlockFlow::addOverflowFromFloats() void RenderBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats) { RenderBlock::computeOverflow(oldClientAfterEdge, recomputeFloats); - if (!hasColumns() && (recomputeFloats || isRoot() || expandsToEncloseOverhangingFloats() || hasSelfPaintingLayer())) + if (!hasColumns() && (recomputeFloats || createsBlockFormattingContext() || hasSelfPaintingLayer())) addOverflowFromFloats(); } +RootInlineBox* RenderBlockFlow::createAndAppendRootInlineBox() +{ + RootInlineBox* rootBox = createRootInlineBox(); + m_lineBoxes.appendLineBox(rootBox); + + if (UNLIKELY(AXObjectCache::accessibilityEnabled()) && m_lineBoxes.firstLineBox() == rootBox) { + if (AXObjectCache* cache = document().existingAXObjectCache()) + cache->recomputeIsIgnored(this); + } + + return rootBox; +} + void RenderBlockFlow::deleteLineBoxTree() { if (containsFloats()) @@ -1633,11 +1769,10 @@ LayoutUnit RenderBlockFlow::getClearDelta(RenderBox* child, LayoutUnit logicalTo LayoutUnit newLogicalTop = logicalTop; while (true) { LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, false, logicalHeightForChild(child)); - if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop)) + if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent()) return newLogicalTop - logicalTop; - RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child)); - LayoutRect borderBox = child->borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo); + LayoutRect borderBox = child->borderBoxRect(); LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height(); // FIXME: None of this is right for perpendicular writing-mode children. @@ -1648,8 +1783,7 @@ LayoutUnit RenderBlockFlow::getClearDelta(RenderBox* child, LayoutUnit logicalTo child->setLogicalTop(newLogicalTop); child->updateLogicalWidth(); - region = regionAtBlockOffset(logicalTopForChild(child)); - borderBox = child->borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo); + borderBox = child->borderBoxRect(); LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height(); child->setLogicalTop(childOldLogicalTop); @@ -1681,12 +1815,12 @@ void RenderBlockFlow::createFloatingObjects() m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode())); } -void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) +void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle& newStyle) { RenderStyle* oldStyle = style(); s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false; - if (oldStyle && parent() && diff == StyleDifferenceLayout && oldStyle->position() != newStyle->position() - && containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle->hasOutOfFlowPosition()) + if (oldStyle && parent() && diff.needsFullLayout() && oldStyle->position() != newStyle.position() + && containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition()) markAllDescendantsWithFloatsForLayout(); RenderBlock::styleWillChange(diff, newStyle); @@ -1701,7 +1835,7 @@ void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* ol // then mark its descendants with floats for layout and clear all floats from its next // sibling blocks that exist in our floating objects list. See bug 56299 and 62875. bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats(); - if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) { + if (diff.needsFullLayout() && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) { RenderBlockFlow* parentBlockFlow = this; const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); FloatingObjectSetIterator end = floatingObjectSet.end(); @@ -1726,8 +1860,8 @@ void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* ol parentBlockFlow->markSiblingsWithFloatsForLayout(); } - if (renderNamedFlowFragment()) - renderNamedFlowFragment()->setStyleForNamedFlowFragment(style()); + if (diff.needsFullLayout() || !oldStyle) + createOrDestroyMultiColumnFlowThreadIfNeeded(); } void RenderBlockFlow::updateStaticInlinePositionForChild(RenderBox* child, LayoutUnit logicalTop) @@ -1735,18 +1869,23 @@ void RenderBlockFlow::updateStaticInlinePositionForChild(RenderBox* child, Layou if (child->style()->isOriginalDisplayInlineType()) setStaticInlinePositionForChild(child, logicalTop, startAlignedOffsetForLine(logicalTop, false)); else - setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop)); + setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent()); } void RenderBlockFlow::setStaticInlinePositionForChild(RenderBox* child, LayoutUnit blockOffset, LayoutUnit inlinePosition) { - if (flowThreadContainingBlock()) { - // Shift the inline position to exclude the region offset. - inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset); - } child->layer()->setStaticInlinePosition(inlinePosition); } +void RenderBlockFlow::addChild(RenderObject* newChild, RenderObject* beforeChild) +{ + if (RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread()) { + flowThread->addChild(newChild, beforeChild); + return; + } + RenderBlock::addChild(newChild, beforeChild); +} + void RenderBlockFlow::moveAllChildrenIncludingFloatsTo(RenderBlock* toBlock, bool fullRemoveInsert) { RenderBlockFlow* toBlockFlow = toRenderBlockFlow(toBlock); @@ -1777,7 +1916,7 @@ void RenderBlockFlow::moveAllChildrenIncludingFloatsTo(RenderBlock* toBlock, boo FloatingObjectSetIterator end = fromFloatingObjectSet.end(); for (FloatingObjectSetIterator it = fromFloatingObjectSet.begin(); it != end; ++it) { - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); // Don't insert the object again if it's already in the list if (toBlockFlow->containsFloat(floatingObject->renderer())) @@ -1798,11 +1937,11 @@ void RenderBlockFlow::repaintOverhangingFloats(bool paintAllDescendants) // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating // in this block. Better yet would be to push extra state for the containers of other floats. - LayoutStateDisabler layoutStateDisabler(view()); + ForceHorriblySlowRectMapping slowRectMapping(*this); const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); FloatingObjectSetIterator end = floatingObjectSet.end(); for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); // 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. @@ -1811,18 +1950,17 @@ void RenderBlockFlow::repaintOverhangingFloats(bool paintAllDescendants) && (floatingObject->shouldPaint() || (paintAllDescendants && floatingObject->renderer()->isDescendantOf(this)))) { RenderBox* floatingRenderer = floatingObject->renderer(); - LayoutRectRecorder recorder(*floatingRenderer); if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) - floatingRenderer->setShouldDoFullRepaintAfterLayout(true); + floatingRenderer->setShouldDoFullPaintInvalidationAfterLayout(true); else - floatingRenderer->repaint(); + floatingRenderer->paintInvalidationForWholeRenderer(); floatingRenderer->repaintOverhangingFloats(false); } } } -void RenderBlockFlow::repaintOverflow() +void RenderBlockFlow::invalidatePaintForOverflow() { // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either. @@ -1845,8 +1983,6 @@ void RenderBlockFlow::repaintOverflow() // The repaint rect may be split across columns, in which case adjustRectForColumns() will return the union. adjustRectForColumns(repaintRect); - repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline)); - if (hasOverflowClip()) { // Adjust repaint rect for scroll offset repaintRect.move(-scrolledContentOffset()); @@ -1857,9 +1993,12 @@ void RenderBlockFlow::repaintOverflow() // Make sure the rect is still non-empty after intersecting for overflow above if (!repaintRect.isEmpty()) { - repaintRectangle(repaintRect); // We need to do a partial repaint of our content. + // Hits in media/event-attributes.html + DisableCompositingQueryAsserts disabler; + + invalidatePaintRectangle(repaintRect); // We need to do a partial repaint of our content. if (hasReflection()) - repaintRectangle(reflectedRect(repaintRect)); + invalidatePaintRectangle(reflectedRect(repaintRect)); } m_repaintLogicalTop = 0; @@ -1874,7 +2013,7 @@ void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paint const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); FloatingObjectSetIterator end = floatingObjectSet.end(); for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); // Only paint the object if our m_shouldPaint flag is set. if (floatingObject->shouldPaint() && !floatingObject->renderer()->hasSelfPaintingLayer()) { PaintInfo currentPaintInfo(paintInfo); @@ -1902,7 +2041,7 @@ void RenderBlockFlow::clipOutFloatingObjects(RenderBlock* rootBlock, const Paint const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); FloatingObjectSetIterator end = floatingObjectSet.end(); for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(floatingObject), offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(floatingObject), floatingObject->renderer()->width(), floatingObject->renderer()->height()); @@ -1944,6 +2083,8 @@ void RenderBlockFlow::removeFloatingObjects() if (!m_floatingObjects) return; + markSiblingsWithFloatsForLayout(); + m_floatingObjects->clear(); } @@ -1976,34 +2117,32 @@ LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit log return adjustLogicalRightOffsetForLine(offset, applyTextIndent); } +LayoutUnit RenderBlockFlow::adjustLogicalLeftOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const +{ + LayoutUnit left = offsetFromFloats; + + if (applyTextIndent && style()->isLeftToRightDirection()) + left += textIndentOffset(); + + return left; +} + +LayoutUnit RenderBlockFlow::adjustLogicalRightOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const +{ + LayoutUnit right = offsetFromFloats; + + if (applyTextIndent && !style()->isLeftToRightDirection()) + right -= textIndentOffset(); + + return right; +} + LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset) const { RenderBox* childBox = floatingObject->renderer(); - LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset. + LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(); // Constant part of left offset. LayoutUnit logicalRightOffset; // Constant part of right offset. - // FIXME Bug 102948: This only works for shape outside directly set on this block. - ShapeInsideInfo* shapeInsideInfo = this->layoutShapeInsideInfo(); - // FIXME: Implement behavior for right floats. - if (shapeInsideInfo) { - LayoutSize floatLogicalSize = logicalSizeForFloat(floatingObject); - // floatingObject's logicalSize doesn't contain the actual height at this point, so we need to calculate it - floatLogicalSize.setHeight(logicalHeightForChild(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox)); - - // FIXME: If the float doesn't fit in the shape we should push it under the content box - logicalTopOffset = shapeInsideInfo->computeFirstFitPositionForFloat(floatLogicalSize); - if (logicalHeight() > logicalTopOffset) - logicalTopOffset = logicalHeight(); - - SegmentList segments = shapeInsideInfo->computeSegmentsForLine(logicalTopOffset, floatLogicalSize.height()); - // FIXME: Add support for shapes with multiple segments. - if (segments.size() == 1) { - // The segment offsets are relative to the content box. - logicalRightOffset = logicalLeftOffset + segments[0].logicalRight; - logicalLeftOffset += segments[0].logicalLeft; - } - } else { - logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); - } + logicalRightOffset = logicalRightOffsetForContent(); LayoutUnit floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for. @@ -2020,8 +2159,8 @@ LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft); if (insideFlowThread) { // Have to re-evaluate all of our offsets, since they may have changed. - logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset. - logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset. + logicalRightOffset = logicalRightOffsetForContent(); // Constant part of right offset. + logicalLeftOffset = logicalLeftOffsetForContent(); // Constant part of left offset. floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); } } @@ -2035,8 +2174,8 @@ LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight); if (insideFlowThread) { // Have to re-evaluate all of our offsets, since they may have changed. - logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset. - logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset. + logicalRightOffset = logicalRightOffsetForContent(); // Constant part of right offset. + logicalLeftOffset = logicalLeftOffsetForContent(); // Constant part of left offset. floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); } } @@ -2061,7 +2200,7 @@ FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox* floatBox) const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); FloatingObjectSetIterator it = floatingObjectSet.find<FloatingObjectHashTranslator>(floatBox); if (it != floatingObjectSet.end()) - return *it; + return it->get(); } // Create the special object entry & append it to the list @@ -2093,7 +2232,7 @@ void RenderBlockFlow::removeFloatingObject(RenderBox* floatBox) const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); FloatingObjectSetIterator it = floatingObjectSet.find<FloatingObjectHashTranslator>(floatBox); if (it != floatingObjectSet.end()) { - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); if (childrenInline()) { LayoutUnit logicalTop = logicalTopForFloat(floatingObject); LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject); @@ -2112,7 +2251,7 @@ void RenderBlockFlow::removeFloatingObject(RenderBox* floatBox) ASSERT(floatingObject->originatingLine()->renderer() == this); floatingObject->originatingLine()->markDirty(); } -#if !ASSERT_DISABLED +#if ASSERT_ENABLED floatingObject->setOriginatingLine(0); #endif } @@ -2129,12 +2268,12 @@ void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int return; const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); - FloatingObject* curr = floatingObjectSet.last(); + FloatingObject* curr = floatingObjectSet.last().get(); while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) { m_floatingObjects->remove(curr); if (floatingObjectSet.isEmpty()) break; - curr = floatingObjectSet.last(); + curr = floatingObjectSet.last().get(); } } @@ -2161,7 +2300,7 @@ bool RenderBlockFlow::positionNewFloats() while (it != begin) { --it; if ((*it)->isPlaced()) { - lastPlacedFloatingObject = *it; + lastPlacedFloatingObject = it->get(); ++it; break; } @@ -2176,15 +2315,18 @@ bool RenderBlockFlow::positionNewFloats() FloatingObjectSetIterator end = floatingObjectSet.end(); // Now walk through the set of unpositioned floats and place them. for (; it != end; ++it) { - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); // 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. if (floatingObject->renderer()->containingBlock() != this) continue; RenderBox* childBox = floatingObject->renderer(); - LayoutUnit childLogicalLeftMargin = style()->isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox); + // FIXME Investigate if this can be removed. crbug.com/370006 + childBox->setMayNeedPaintInvalidation(true); + + LayoutUnit childLogicalLeftMargin = style()->isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox); LayoutRect oldRect = childBox->frameRect(); if (childBox->style()->clear() & CLEFT) @@ -2199,7 +2341,7 @@ bool RenderBlockFlow::positionNewFloats() setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin); setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox)); - SubtreeLayoutScope layoutScope(childBox); + SubtreeLayoutScope layoutScope(*childBox); LayoutState* layoutState = view()->layoutState(); bool isPaginated = layoutState->isPaginated(); if (isPaginated && !childBox->needsLayout()) @@ -2243,10 +2385,11 @@ bool RenderBlockFlow::positionNewFloats() m_floatingObjects->addPlacedObject(floatingObject); if (ShapeOutsideInfo* shapeOutside = childBox->shapeOutsideInfo()) - shapeOutside->setShapeSize(logicalWidthForChild(childBox), logicalHeightForChild(childBox)); + shapeOutside->setReferenceBoxLogicalSize(logicalSizeForChild(childBox)); // If the child moved, we have to repaint it. - if (childBox->checkForRepaintDuringLayout()) + if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled() + && childBox->checkForPaintInvalidationDuringLayout()) childBox->repaintDuringLayoutIfMoved(oldRect); } return true; @@ -2262,13 +2405,17 @@ bool RenderBlockFlow::hasOverhangingFloat(RenderBox* renderer) if (it == floatingObjectSet.end()) return false; - return logicalBottomForFloat(*it) > logicalHeight(); + return logicalBottomForFloat(it->get()) > logicalHeight(); } void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset) { ASSERT(!avoidsFloats()); + // If we create our own block formatting context then our contents don't interact with floats outside it, even those from our parent. + if (createsBlockFormattingContext()) + return; + // If the parent or previous sibling doesn't have any floats to add, don't bother. if (!prev->m_floatingObjects) return; @@ -2278,7 +2425,7 @@ void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, LayoutUnit logic const FloatingObjectSet& prevSet = prev->m_floatingObjects->set(); FloatingObjectSetIterator prevEnd = prevSet.end(); for (FloatingObjectSetIterator prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) { - FloatingObject* floatingObject = *prevIt; + FloatingObject* floatingObject = prevIt->get(); if (logicalBottomForFloat(floatingObject) > logicalTopOffset) { if (!m_floatingObjects || !m_floatingObjects->set().contains(floatingObject)) { // We create the floating object list lazily. @@ -2300,24 +2447,22 @@ void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, LayoutUnit logic } } -LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow* child, bool makeChildPaintOtherFloats) +void RenderBlockFlow::addOverhangingFloats(RenderBlockFlow* child, bool makeChildPaintOtherFloats) { // Prevent floats from being added to the canvas by the root element, e.g., <html>. - if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot() || child->hasColumns() || child->isWritingModeRoot()) - return 0; + if (!child->containsFloats() || child->isRenderRegion() || child->createsBlockFormattingContext()) + return; LayoutUnit childLogicalTop = child->logicalTop(); LayoutUnit childLogicalLeft = child->logicalLeft(); - LayoutUnit lowestFloatLogicalBottom = 0; // Floats that will remain the child's responsibility to paint should factor into its // overflow. FloatingObjectSetIterator childEnd = child->m_floatingObjects->set().end(); for (FloatingObjectSetIterator childIt = child->m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) { - FloatingObject* floatingObject = *childIt; + FloatingObject* floatingObject = childIt->get(); LayoutUnit logicalBottomForFloat = min(this->logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop); LayoutUnit logicalBottom = childLogicalTop + logicalBottomForFloat; - lowestFloatLogicalBottom = max(lowestFloatLogicalBottom, logicalBottom); if (logicalBottom > logicalHeight()) { // If the object is not in the list, we add it now. @@ -2356,7 +2501,6 @@ LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow* child, bool ma child->addOverflowFromChild(floatingObject->renderer(), LayoutSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject))); } } - return lowestFloatLogicalBottom; } LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) const @@ -2372,11 +2516,11 @@ LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight if (!m_floatingObjects) return logicalHeight; - LayoutUnit logicalBottom = LayoutUnit::max(); + LayoutUnit logicalBottom; const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); FloatingObjectSetIterator end = floatingObjectSet.end(); for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); LayoutUnit floatLogicalBottom = logicalBottomForFloat(floatingObject); ShapeOutsideInfo* shapeOutside = floatingObject->renderer()->shapeOutsideInfo(); if (shapeOutside && (offsetMode == ShapeOutsideFloatShapeOffset)) { @@ -2386,10 +2530,10 @@ LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight floatLogicalBottom = shapeLogicalBottom; } if (floatLogicalBottom > logicalHeight) - logicalBottom = min(floatLogicalBottom, logicalBottom); + logicalBottom = logicalBottom ? min(floatLogicalBottom, logicalBottom) : floatLogicalBottom; } - return logicalBottom == LayoutUnit::max() ? LayoutUnit() : logicalBottom; + return logicalBottom; } bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) @@ -2406,7 +2550,7 @@ bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult FloatingObjectSetIterator begin = floatingObjectSet.begin(); for (FloatingObjectSetIterator it = floatingObjectSet.end(); it != begin;) { --it; - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); if (floatingObject->shouldPaint() && !floatingObject->renderer()->hasSelfPaintingLayer()) { LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer()->x(); LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer()->y(); @@ -2428,7 +2572,7 @@ void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutU const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); FloatingObjectSetIterator end = floatingObjectSet.end(); for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); // Only examine the object if our m_shouldPaint flag is set. if (floatingObject->shouldPaint()) { LayoutUnit floatLeft = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer()->x(); @@ -2512,12 +2656,40 @@ GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock* rootBlock, const Layo return result; } +LayoutUnit RenderBlockFlow::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position) +{ + LayoutUnit logicalLeft = logicalLeftOffsetForLine(position, false); + if (logicalLeft == logicalLeftOffsetForContent()) + return RenderBlock::logicalLeftSelectionOffset(rootBlock, position); + + RenderBlock* cb = this; + while (cb != rootBlock) { + logicalLeft += cb->logicalLeft(); + cb = cb->containingBlock(); + } + return logicalLeft; +} + +LayoutUnit RenderBlockFlow::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position) +{ + LayoutUnit logicalRight = logicalRightOffsetForLine(position, false); + if (logicalRight == logicalRightOffsetForContent()) + return RenderBlock::logicalRightSelectionOffset(rootBlock, position); + + RenderBlock* cb = this; + while (cb != rootBlock) { + logicalRight += cb->logicalLeft(); + cb = cb->containingBlock(); + } + return logicalRight; +} + template <typename CharacterType> -static inline TextRun constructTextRunInternal(RenderObject* context, const Font& font, const CharacterType* characters, int length, RenderStyle* style, TextRun::ExpansionBehavior expansion) +static inline TextRun constructTextRunInternal(RenderObject* context, const Font& font, const CharacterType* characters, int length, RenderStyle* style, TextDirection direction, TextRun::ExpansionBehavior expansion) { ASSERT(style); - TextDirection textDirection = LTR; + TextDirection textDirection = direction; bool directionalOverride = style->rtlOrdering() == VisualOrder; TextRun run(characters, length, 0, 0, expansion, textDirection, directionalOverride); @@ -2528,11 +2700,11 @@ static inline TextRun constructTextRunInternal(RenderObject* context, const Font } template <typename CharacterType> -static inline TextRun constructTextRunInternal(RenderObject* context, const Font& font, const CharacterType* characters, int length, RenderStyle* style, TextRun::ExpansionBehavior expansion, TextRunFlags flags) +static inline TextRun constructTextRunInternal(RenderObject* context, const Font& font, const CharacterType* characters, int length, RenderStyle* style, TextDirection direction, TextRun::ExpansionBehavior expansion, TextRunFlags flags) { ASSERT(style); - TextDirection textDirection = LTR; + TextDirection textDirection = direction; bool directionalOverride = style->rtlOrdering() == VisualOrder; if (flags != DefaultTextRunFlags) { if (flags & RespectDirection) @@ -2542,109 +2714,90 @@ static inline TextRun constructTextRunInternal(RenderObject* context, const Font } TextRun run(characters, length, 0, 0, expansion, textDirection, directionalOverride); - if (!directionalOverride) { - BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver; - bidiResolver.setStatus(BidiStatus(run.direction(), run.directionalOverride())); - bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0)); - bool hasStrongDirectionality; - TextDirection direction = bidiResolver.determineParagraphDirectionality(&hasStrongDirectionality); - if (hasStrongDirectionality) - run.setDirection(direction); - } - if (textRunNeedsRenderingContext(font)) run.setRenderingContext(SVGTextRunRenderingContext::create(context)); return run; } -TextRun RenderBlockFlow::constructTextRun(RenderObject* context, const Font& font, const LChar* characters, int length, RenderStyle* style, TextRun::ExpansionBehavior expansion) +TextRun RenderBlockFlow::constructTextRun(RenderObject* context, const Font& font, const LChar* characters, int length, RenderStyle* style, TextDirection direction, TextRun::ExpansionBehavior expansion) { - return constructTextRunInternal(context, font, characters, length, style, expansion); + return constructTextRunInternal(context, font, characters, length, style, direction, expansion); } -TextRun RenderBlockFlow::constructTextRun(RenderObject* context, const Font& font, const UChar* characters, int length, RenderStyle* style, TextRun::ExpansionBehavior expansion) +TextRun RenderBlockFlow::constructTextRun(RenderObject* context, const Font& font, const UChar* characters, int length, RenderStyle* style, TextDirection direction, TextRun::ExpansionBehavior expansion) { - return constructTextRunInternal(context, font, characters, length, style, expansion); + return constructTextRunInternal(context, font, characters, length, style, direction, expansion); } -TextRun RenderBlockFlow::constructTextRun(RenderObject* context, const Font& font, const RenderText* text, RenderStyle* style, TextRun::ExpansionBehavior expansion) +TextRun RenderBlockFlow::constructTextRun(RenderObject* context, const Font& font, const RenderText* text, RenderStyle* style, TextDirection direction, TextRun::ExpansionBehavior expansion) { if (text->is8Bit()) - return constructTextRunInternal(context, font, text->characters8(), text->textLength(), style, expansion); - return constructTextRunInternal(context, font, text->characters16(), text->textLength(), style, expansion); + return constructTextRunInternal(context, font, text->characters8(), text->textLength(), style, direction, expansion); + return constructTextRunInternal(context, font, text->characters16(), text->textLength(), style, direction, expansion); } -TextRun RenderBlockFlow::constructTextRun(RenderObject* context, const Font& font, const RenderText* text, unsigned offset, unsigned length, RenderStyle* style, TextRun::ExpansionBehavior expansion) +TextRun RenderBlockFlow::constructTextRun(RenderObject* context, const Font& font, const RenderText* text, unsigned offset, unsigned length, RenderStyle* style, TextDirection direction, TextRun::ExpansionBehavior expansion) { ASSERT(offset + length <= text->textLength()); if (text->is8Bit()) - return constructTextRunInternal(context, font, text->characters8() + offset, length, style, expansion); - return constructTextRunInternal(context, font, text->characters16() + offset, length, style, expansion); + return constructTextRunInternal(context, font, text->characters8() + offset, length, style, direction, expansion); + return constructTextRunInternal(context, font, text->characters16() + offset, length, style, direction, expansion); } -TextRun RenderBlockFlow::constructTextRun(RenderObject* context, const Font& font, const String& string, RenderStyle* style, TextRun::ExpansionBehavior expansion, TextRunFlags flags) +TextRun RenderBlockFlow::constructTextRun(RenderObject* context, const Font& font, const String& string, RenderStyle* style, TextDirection direction, TextRun::ExpansionBehavior expansion, TextRunFlags flags) { unsigned length = string.length(); if (!length) - return constructTextRunInternal(context, font, static_cast<const LChar*>(0), length, style, expansion, flags); + return constructTextRunInternal(context, font, static_cast<const LChar*>(0), length, style, direction, expansion, flags); if (string.is8Bit()) - return constructTextRunInternal(context, font, string.characters8(), length, style, expansion, flags); - return constructTextRunInternal(context, font, string.characters16(), length, style, expansion, flags); -} - -RootInlineBox* RenderBlockFlow::createRootInlineBox() -{ - return new RootInlineBox(this); -} - -void RenderBlockFlow::createRenderNamedFlowFragmentIfNeeded() -{ - if (!RuntimeEnabledFeatures::cssRegionsEnabled() - || renderNamedFlowFragment() - || isRenderNamedFlowFragment()) - return; - - RenderStyle* styleToUse = style(); - if (styleToUse->isDisplayRegionType() && styleToUse->hasFlowFrom() && document().renderView()) { - RenderNamedFlowFragment* flowFragment = RenderNamedFlowFragment::createAnonymous(&document()); - flowFragment->setStyleForNamedFlowFragment(styleToUse); - setRenderNamedFlowFragment(flowFragment); - addChild(flowFragment); - } + return constructTextRunInternal(context, font, string.characters8(), length, style, direction, expansion, flags); + return constructTextRunInternal(context, font, string.characters16(), length, style, direction, expansion, flags); } -void RenderBlockFlow::insertedIntoTree() +TextRun RenderBlockFlow::constructTextRun(RenderObject* context, const Font& font, const String& string, RenderStyle* style, TextRun::ExpansionBehavior expansion, TextRunFlags flags) { - RenderBlock::insertedIntoTree(); - - createRenderNamedFlowFragmentIfNeeded(); + bool hasStrongDirectionality; + return constructTextRun(context, font, string, style, + determineDirectionality(string, hasStrongDirectionality), + expansion, flags); } -bool RenderBlockFlow::canHaveChildren() const +TextRun RenderBlockFlow::constructTextRun(RenderObject* context, const Font& font, const RenderText* text, unsigned offset, unsigned length, RenderStyle* style, TextRun::ExpansionBehavior expansion) { - return !renderNamedFlowFragment() ? RenderBlock::canHaveChildren() : renderNamedFlowFragment()->canHaveChildren(); + ASSERT(offset + length <= text->textLength()); + TextRun run = text->is8Bit() + ? constructTextRunInternal(context, font, text->characters8() + offset, length, style, LTR, expansion) + : constructTextRunInternal(context, font, text->characters16() + offset, length, style, LTR, expansion); + bool hasStrongDirectionality; + run.setDirection(directionForRun(run, hasStrongDirectionality)); + return run; } -bool RenderBlockFlow::canHaveGeneratedChildren() const +RootInlineBox* RenderBlockFlow::createRootInlineBox() { - return !renderNamedFlowFragment() ? RenderBlock::canHaveGeneratedChildren() : renderNamedFlowFragment()->canHaveGeneratedChildren(); + return new RootInlineBox(*this); } -void RenderBlockFlow::updateLogicalHeight() +void RenderBlockFlow::createOrDestroyMultiColumnFlowThreadIfNeeded() { - RenderBlock::updateLogicalHeight(); - - if (renderNamedFlowFragment()) - renderNamedFlowFragment()->setLogicalHeight(max<LayoutUnit>(0, logicalHeight() - borderAndPaddingLogicalHeight())); -} + if (!document().regionBasedColumnsEnabled()) + return; -void RenderBlockFlow::setRenderNamedFlowFragment(RenderNamedFlowFragment* flowFragment) -{ - RenderBlockFlow::RenderBlockFlowRareData& rareData = ensureRareData(); - if (rareData.m_renderNamedFlowFragment) - rareData.m_renderNamedFlowFragment->destroy(); - rareData.m_renderNamedFlowFragment = flowFragment; + bool needsFlowThread = style()->specifiesColumns(); + if (needsFlowThread != static_cast<bool>(multiColumnFlowThread())) { + if (needsFlowThread) { + RenderMultiColumnFlowThread* flowThread = RenderMultiColumnFlowThread::createAnonymous(document(), style()); + addChild(flowThread); + flowThread->populate(); + RenderBlockFlowRareData& rareData = ensureRareData(); + ASSERT(!rareData.m_multiColumnFlowThread); + rareData.m_multiColumnFlowThread = flowThread; + } else { + multiColumnFlowThread()->evacuateAndDestroy(); + ASSERT(!multiColumnFlowThread()); + } + } } RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareData() diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderBlockFlow.h b/chromium/third_party/WebKit/Source/core/rendering/RenderBlockFlow.h index e68388194f5..2f94081d965 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderBlockFlow.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderBlockFlow.h @@ -38,6 +38,7 @@ #include "core/rendering/FloatingObjects.h" #include "core/rendering/RenderBlock.h" +#include "core/rendering/line/TrailingObjects.h" #include "core/rendering/style/RenderStyleConstants.h" namespace WebCore { @@ -45,7 +46,7 @@ namespace WebCore { class MarginInfo; class LineBreaker; class LineWidth; -class RenderNamedFlowFragment; +class RenderMultiColumnFlowThread; class RenderBlockFlow : public RenderBlock { public: @@ -53,15 +54,44 @@ public: virtual ~RenderBlockFlow(); static RenderBlockFlow* createAnonymous(Document*); - RenderBlockFlow* createAnonymousBlockFlow() const; virtual bool isRenderBlockFlow() const OVERRIDE FINAL { return true; } - virtual void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0) OVERRIDE; + virtual void layoutBlock(bool relayoutChildren) OVERRIDE; virtual void computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats = false) OVERRIDE; virtual void deleteLineBoxTree() OVERRIDE FINAL; + LayoutUnit availableLogicalWidthForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const + { + return max<LayoutUnit>(0, logicalRightOffsetForLine(position, shouldIndentText, logicalHeight) - logicalLeftOffsetForLine(position, shouldIndentText, logicalHeight)); + } + LayoutUnit logicalRightOffsetForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const + { + return logicalRightOffsetForLine(position, logicalRightOffsetForContent(), shouldIndentText, logicalHeight); + } + LayoutUnit logicalLeftOffsetForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const + { + return logicalLeftOffsetForLine(position, logicalLeftOffsetForContent(), shouldIndentText, logicalHeight); + } + LayoutUnit startOffsetForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const + { + return style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(position, shouldIndentText, logicalHeight) + : logicalWidth() - logicalRightOffsetForLine(position, shouldIndentText, logicalHeight); + } + LayoutUnit endOffsetForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const + { + return !style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(position, shouldIndentText, logicalHeight) + : logicalWidth() - logicalRightOffsetForLine(position, shouldIndentText, logicalHeight); + } + + virtual LayoutUnit logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position) OVERRIDE; + virtual LayoutUnit logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position) OVERRIDE; + + LayoutUnit computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart); + + RootInlineBox* createAndAppendRootInlineBox(); + void markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove = 0, bool inLayout = true); void markSiblingsWithFloatsForLayout(RenderBox* floatToRemove = 0); @@ -70,6 +100,10 @@ public: void removeFloatingObjects(); + virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0) OVERRIDE; + + void moveAllChildrenIncludingFloatsTo(RenderBlock* toBlock, bool fullRemoveInsert); + bool generatesLineBoxesForInlineChild(RenderObject*); LayoutUnit logicalTopForFloat(const FloatingObject* floatingObject) const { return isHorizontalWritingMode() ? floatingObject->y() : floatingObject->x(); } @@ -124,67 +158,82 @@ public: return obj->isFloating() || (obj->isOutOfFlowPositioned() && !obj->style()->isOriginalDisplayInlineType() && !obj->container()->isRenderInline()); } + // Direction resolved from string value. static TextRun constructTextRun(RenderObject* context, const Font&, const String&, RenderStyle*, TextRun::ExpansionBehavior = TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion, TextRunFlags = DefaultTextRunFlags); + static TextRun constructTextRun(RenderObject* context, const Font&, const RenderText*, unsigned offset, unsigned length, RenderStyle*, + TextRun::ExpansionBehavior = TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion); - static TextRun constructTextRun(RenderObject* context, const Font&, const RenderText*, RenderStyle*, + // Explicit direction. + static TextRun constructTextRun(RenderObject* context, const Font&, const String&, RenderStyle*, TextDirection, + TextRun::ExpansionBehavior = TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion, TextRunFlags = DefaultTextRunFlags); + + static TextRun constructTextRun(RenderObject* context, const Font&, const RenderText*, RenderStyle*, TextDirection, TextRun::ExpansionBehavior = TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion); - static TextRun constructTextRun(RenderObject* context, const Font&, const RenderText*, unsigned offset, unsigned length, RenderStyle*, + static TextRun constructTextRun(RenderObject* context, const Font&, const RenderText*, unsigned offset, unsigned length, RenderStyle*, TextDirection, TextRun::ExpansionBehavior = TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion); static TextRun constructTextRun(RenderObject* context, const Font&, const RenderText*, unsigned offset, RenderStyle*, TextRun::ExpansionBehavior = TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion); - static TextRun constructTextRun(RenderObject* context, const Font&, const LChar* characters, int length, RenderStyle*, + static TextRun constructTextRun(RenderObject* context, const Font&, const LChar* characters, int length, RenderStyle*, TextDirection, TextRun::ExpansionBehavior = TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion); - static TextRun constructTextRun(RenderObject* context, const Font&, const UChar* characters, int length, RenderStyle*, + static TextRun constructTextRun(RenderObject* context, const Font&, const UChar* characters, int length, RenderStyle*, TextDirection, TextRun::ExpansionBehavior = TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion); - RootInlineBox* lineGridBox() const { return m_rareData ? m_rareData->m_lineGridBox : 0; } - void setLineGridBox(RootInlineBox* box) + RenderMultiColumnFlowThread* multiColumnFlowThread() const { return m_rareData ? m_rareData->m_multiColumnFlowThread : 0; } + void resetMultiColumnFlowThread() { - RenderBlockFlow::RenderBlockFlowRareData& rareData = ensureRareData(); - if (rareData.m_lineGridBox) - rareData.m_lineGridBox->destroy(); - rareData.m_lineGridBox = box; + if (m_rareData) + m_rareData->m_multiColumnFlowThread = 0; } - void layoutLineGridBox(); void addOverflowFromInlineChildren(); + // FIXME: This should be const to avoid a const_cast, but can modify child dirty bits and RenderCombineText + void computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth); + GapRects inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo*); protected: - // Only used by RenderSVGText, which explicitly overrides RenderBlock::layoutBlock(), do NOT use for anything else. - void forceLayoutInlineChildren() - { - LayoutUnit repaintLogicalTop = 0; - LayoutUnit repaintLogicalBottom = 0; - rebuildFloatsFromIntruding(); - layoutInlineChildren(true, repaintLogicalTop, repaintLogicalBottom); - } + void rebuildFloatsFromIntruding(); + void layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom, LayoutUnit afterEdge); void createFloatingObjects(); - virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle) OVERRIDE; + virtual void styleWillChange(StyleDifference, const RenderStyle& newStyle) OVERRIDE; virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; void addOverflowFromFloats(); - virtual void insertedIntoTree() OVERRIDE; - virtual void willBeDestroyed() OVERRIDE; + LayoutUnit logicalRightOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit logicalHeight = 0) const + { + return adjustLogicalRightOffsetForLine(logicalRightFloatOffsetForLine(logicalTop, fixedOffset, logicalHeight), applyTextIndent); + } + LayoutUnit logicalLeftOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit logicalHeight = 0) const + { + return adjustLogicalLeftOffsetForLine(logicalLeftFloatOffsetForLine(logicalTop, fixedOffset, logicalHeight), applyTextIndent); + } + + virtual RenderObject* layoutSpecialExcludedChild(bool /*relayoutChildren*/, SubtreeLayoutScope&); + virtual bool updateLogicalWidthAndColumnWidth() OVERRIDE; + + // These functions optionally update LayoutState's layoutDelta, which is used to ensure they're repainted correctly when moved + enum ApplyLayoutDeltaMode { ApplyLayoutDelta, DoNotApplyLayoutDelta }; + void setLogicalLeftForChild(RenderBox* child, LayoutUnit logicalLeft, ApplyLayoutDeltaMode = DoNotApplyLayoutDelta); + void setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop, ApplyLayoutDeltaMode = DoNotApplyLayoutDelta); + void determineLogicalLeftPositionForChild(RenderBox* child, ApplyLayoutDeltaMode = DoNotApplyLayoutDelta); + private: - void layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom, SubtreeLayoutScope&); - void layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom); + bool layoutBlockFlow(bool relayoutChildren, LayoutUnit& pageLogicalHeight, SubtreeLayoutScope&); + void layoutBlockChildren(bool relayoutChildren, SubtreeLayoutScope&, LayoutUnit beforeEdge, LayoutUnit afterEdge); - void layoutBlockChild(RenderBox* child, MarginInfo&, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom); + void layoutBlockChild(RenderBox* child, MarginInfo&, LayoutUnit& previousFloatLogicalBottom); void adjustPositionedBlock(RenderBox* child, const MarginInfo&); void adjustFloatingBlock(const MarginInfo&); - void rebuildFloatsFromIntruding(); - LayoutPoint flipFloatForWritingModeForChild(const FloatingObject*, const LayoutPoint&) const; LayoutUnit xPositionForFloatIncludingMargin(const FloatingObject* child) const @@ -218,32 +267,39 @@ private: bool hasOverhangingFloats() { return parent() && !hasColumns() && containsFloats() && lowestFloatLogicalBottom() > logicalHeight(); } bool hasOverhangingFloat(RenderBox*); void addIntrudingFloats(RenderBlockFlow* prev, LayoutUnit xoffset, LayoutUnit yoffset); - LayoutUnit addOverhangingFloats(RenderBlockFlow* child, bool makeChildPaintOtherFloats); + void addOverhangingFloats(RenderBlockFlow* child, bool makeChildPaintOtherFloats); LayoutUnit lowestFloatLogicalBottom(FloatingObject::Type = FloatingObject::FloatLeftRight) const; LayoutUnit nextFloatLogicalBottomBelow(LayoutUnit, ShapeOutsideFloatOffsetMode = ShapeOutsideFloatMarginBoxOffset) const; virtual bool hitTestFloats(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) OVERRIDE FINAL; - virtual void moveAllChildrenIncludingFloatsTo(RenderBlock* toBlock, bool fullRemoveInsert) OVERRIDE; virtual void repaintOverhangingFloats(bool paintAllDescendants) OVERRIDE FINAL; - virtual void repaintOverflow() OVERRIDE; + virtual void invalidatePaintForOverflow() OVERRIDE FINAL; virtual void paintFloats(PaintInfo&, const LayoutPoint&, bool preservePhase = false) OVERRIDE FINAL; virtual void clipOutFloatingObjects(RenderBlock*, const PaintInfo*, const LayoutPoint&, const LayoutSize&) OVERRIDE; void clearFloats(EClear); - virtual LayoutUnit logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const OVERRIDE; - virtual LayoutUnit logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const OVERRIDE; + LayoutUnit logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const; + LayoutUnit logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const; LayoutUnit logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const; LayoutUnit logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const; + LayoutUnit adjustLogicalRightOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const; + LayoutUnit adjustLogicalLeftOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const; + virtual void adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const OVERRIDE; // Helper function for borderFitAdjust - virtual RootInlineBox* createRootInlineBox() OVERRIDE; + virtual RootInlineBox* createRootInlineBox(); // Subclassed by SVG + + void createOrDestroyMultiColumnFlowThreadIfNeeded(); + + void updateLogicalWidthForAlignment(const ETextAlign&, const RootInlineBox*, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float& availableLogicalWidth, unsigned expansionOpportunityCount); + void checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight); + bool shouldRelayoutForPagination(LayoutUnit& pageLogicalHeight, LayoutUnit layoutOverflowLogicalBottom) const; + void setColumnCountAndHeight(unsigned count, LayoutUnit pageLogicalHeight); - void updateLogicalWidthForAlignment(const ETextAlign&, const RootInlineBox*, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float& availableLogicalWidth, int expansionOpportunityCount); - virtual bool relayoutForPagination(bool hasSpecifiedPageLogicalHeight, LayoutUnit pageLogicalHeight, LayoutStateMaintainer&); public: struct FloatWithRect { FloatWithRect(RenderBox* f) @@ -285,18 +341,15 @@ public: }; MarginValues marginValuesForChild(RenderBox* child) const; - virtual void updateLogicalHeight() OVERRIDE; - // Allocated only when some of these fields have non-default values struct RenderBlockFlowRareData { WTF_MAKE_NONCOPYABLE(RenderBlockFlowRareData); WTF_MAKE_FAST_ALLOCATED; public: RenderBlockFlowRareData(const RenderBlockFlow* block) : m_margins(positiveMarginBeforeDefault(block), negativeMarginBeforeDefault(block), positiveMarginAfterDefault(block), negativeMarginAfterDefault(block)) - , m_lineGridBox(0) + , m_multiColumnFlowThread(0) , m_discardMarginBefore(false) , m_discardMarginAfter(false) - , m_renderNamedFlowFragment(0) { } @@ -319,17 +372,13 @@ public: MarginValues m_margins; - RootInlineBox* m_lineGridBox; + RenderMultiColumnFlowThread* m_multiColumnFlowThread; bool m_discardMarginBefore : 1; bool m_discardMarginAfter : 1; - RenderNamedFlowFragment* m_renderNamedFlowFragment; }; LayoutUnit marginOffsetForSelfCollapsingBlock(); - RenderNamedFlowFragment* renderNamedFlowFragment() const { return m_rareData ? m_rareData->m_renderNamedFlowFragment : 0; } - void setRenderNamedFlowFragment(RenderNamedFlowFragment*); - protected: LayoutUnit maxPositiveMarginBefore() const { return m_rareData ? m_rareData->m_margins.positiveMarginBefore() : RenderBlockFlowRareData::positiveMarginBeforeDefault(this); } LayoutUnit maxNegativeMarginBefore() const { return m_rareData ? m_rareData->m_margins.negativeMarginBefore() : RenderBlockFlowRareData::negativeMarginBeforeDefault(this); } @@ -367,11 +416,11 @@ private: virtual LayoutUnit collapsedMarginBefore() const OVERRIDE FINAL { return maxPositiveMarginBefore() - maxNegativeMarginBefore(); } virtual LayoutUnit collapsedMarginAfter() const OVERRIDE FINAL { return maxPositiveMarginAfter() - maxNegativeMarginAfter(); } - LayoutUnit collapseMargins(RenderBox* child, MarginInfo&); - LayoutUnit clearFloatsIfNeeded(RenderBox* child, MarginInfo&, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos); + LayoutUnit collapseMargins(RenderBox* child, MarginInfo&, bool childIsSelfCollapsing); + LayoutUnit clearFloatsIfNeeded(RenderBox* child, MarginInfo&, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos, bool childIsSelfCollapsing); LayoutUnit estimateLogicalTopPosition(RenderBox* child, const MarginInfo&, LayoutUnit& estimateWithoutPagination); void marginBeforeEstimateForChild(RenderBox*, LayoutUnit&, LayoutUnit&, bool&) const; - void handleAfterSideOfBlock(LayoutUnit top, LayoutUnit bottom, MarginInfo&); + void handleAfterSideOfBlock(RenderBox* lastChild, LayoutUnit top, LayoutUnit bottom, MarginInfo&); void setCollapsedBottomMargin(const MarginInfo&); LayoutUnit applyBeforeBreak(RenderBox* child, LayoutUnit logicalOffset); // If the child has a before break, then return a new yPos that shifts to the top of the next page/column. @@ -382,16 +431,12 @@ private: // Used to store state between styleWillChange and styleDidChange static bool s_canPropagateFloatIntoSibling; - virtual bool canHaveChildren() const OVERRIDE; - virtual bool canHaveGeneratedChildren() const OVERRIDE; - - void createRenderNamedFlowFragmentIfNeeded(); - RenderBlockFlowRareData& ensureRareData(); LayoutUnit m_repaintLogicalTop; LayoutUnit m_repaintLogicalBottom; + virtual bool isSelfCollapsingBlock() const OVERRIDE; protected: OwnPtr<RenderBlockFlowRareData> m_rareData; OwnPtr<FloatingObjects> m_floatingObjects; @@ -406,7 +451,7 @@ protected: // line layout code is separated from RenderBlock and RenderBlockFlow. // START METHODS DEFINED IN RenderBlockLineLayout private: - InlineFlowBox* createLineBoxes(RenderObject*, const LineInfo&, InlineBox* childBox, bool startsNewSegment); + InlineFlowBox* createLineBoxes(RenderObject*, const LineInfo&, InlineBox* childBox); RootInlineBox* constructLine(BidiRunList<BidiRun>&, const LineInfo&); void setMarginsForRubyRun(BidiRun*, RenderRubyRun*, RenderObject*, const LineInfo&); void computeInlineDirectionPositionsForLine(RootInlineBox*, const LineInfo&, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&, WordMeasurements&); @@ -417,12 +462,9 @@ private: void appendFloatingObjectToLastLine(FloatingObject*); // Helper function for layoutInlineChildren() RootInlineBox* createLineBoxesFromBidiRuns(unsigned bidiLevel, BidiRunList<BidiRun>&, const InlineIterator& end, LineInfo&, VerticalPositionCache&, BidiRun* trailingSpaceRun, WordMeasurements&); - void layoutRunsAndFloats(LineLayoutState&, bool hasInlineChild); + void layoutRunsAndFloats(LineLayoutState&); const InlineIterator& restartLayoutRunsAndFloatsInRange(LayoutUnit oldLogicalHeight, LayoutUnit newLogicalHeight, FloatingObject* lastFloatFromPreviousLine, InlineBidiResolver&, const InlineIterator&); void layoutRunsAndFloatsInRange(LineLayoutState&, InlineBidiResolver&, const InlineIterator& cleanLineStart, const BidiStatus& cleanLineBidiStatus, unsigned consecutiveHyphenatedLines); - void updateShapeAndSegmentsForCurrentLine(ShapeInsideInfo*&, const LayoutSize&, LineLayoutState&); - void updateShapeAndSegmentsForCurrentLineInFlowThread(ShapeInsideInfo*&, LineLayoutState&); - bool adjustLogicalLineTopAndLogicalHeightIfNeeded(ShapeInsideInfo*, LayoutUnit, LineLayoutState&, InlineBidiResolver&, FloatingObject*, InlineIterator&, WordMeasurements&); void linkToEndLineIfNeeded(LineLayoutState&); static void repaintDirtyFloats(Vector<FloatWithRect>& floats); void checkFloatsInCleanLine(RootInlineBox*, Vector<FloatWithRect>&, size_t& floatIndex, bool& encounteredNewFloat, bool& dirtiedByFloat); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderBlockLineLayout.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderBlockLineLayout.cpp index 9c877c5d802..722299ed03c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderBlockLineLayout.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderBlockLineLayout.cpp @@ -22,8 +22,7 @@ #include "config.h" -#include "core/rendering/FastTextAutosizer.h" -#include "core/rendering/LayoutRectRecorder.h" +#include "core/accessibility/AXObjectCache.h" #include "core/rendering/RenderCounter.h" #include "core/rendering/RenderFlowThread.h" #include "core/rendering/RenderLayer.h" @@ -34,7 +33,12 @@ #include "core/rendering/TrailingFloatsRootInlineBox.h" #include "core/rendering/VerticalPositionCache.h" #include "core/rendering/line/BreakingContextInlineHeaders.h" +#include "core/rendering/line/LineLayoutState.h" +#include "core/rendering/line/LineWidth.h" +#include "core/rendering/line/RenderTextInfo.h" +#include "core/rendering/line/WordMeasurement.h" #include "core/rendering/svg/SVGRootInlineBox.h" +#include "platform/fonts/Character.h" #include "platform/text/BidiResolver.h" #include "wtf/RefCountedLeakCounter.h" #include "wtf/StdLibExtras.h" @@ -43,41 +47,8 @@ namespace WebCore { -static IndentTextOrNot requiresIndent(bool isFirstLine, bool isAfterHardLineBreak, RenderStyle* style) -{ - if (isFirstLine) - return IndentText; - if (isAfterHardLineBreak && style->textIndentLine() == TextIndentEachLine) - return IndentText; - - return DoNotIndentText; -} - -class LineBreaker { -public: - friend class BreakingContext; - LineBreaker(RenderBlockFlow* block) - : m_block(block) - { - reset(); - } - - InlineIterator nextLineBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&); - - bool lineWasHyphenated() { return m_hyphenated; } - const Vector<RenderBox*>& positionedObjects() { return m_positionedObjects; } - EClear clear() { return m_clear; } -private: - void reset(); - - InlineIterator nextSegmentBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&); - void skipLeadingWhitespace(InlineBidiResolver&, LineInfo&, FloatingObject* lastFloatFromPreviousLine, LineWidth&); - - RenderBlockFlow* m_block; - bool m_hyphenated; - EClear m_clear; - Vector<RenderBox*> m_positionedObjects; -}; +using namespace std; +using namespace WTF::Unicode; static RenderObject* firstRenderObjectForDirectionalityDetermination(RenderObject* root, RenderObject* current = 0) { @@ -95,7 +66,7 @@ static RenderObject* firstRenderObjectForDirectionalityDetermination(RenderObjec } if (!current) - current = root->firstChild(); + current = root->slowFirstChild(); while (current) { next = 0; @@ -103,7 +74,7 @@ static RenderObject* firstRenderObjectForDirectionalityDetermination(RenderObjec break; if (!isIteratorTarget(current) && !isIsolated(current->style()->unicodeBidi())) - next = current->firstChild(); + next = current->slowFirstChild(); if (!next) { while (current && current != root) { @@ -135,7 +106,7 @@ static TextDirection determinePlaintextDirectionality(RenderObject* root, Render static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRootLineBox, bool isOnlyRun = false) { if (isRootLineBox) - return toRenderBlock(obj)->createAndAppendRootInlineBox(); + return toRenderBlockFlow(obj)->createAndAppendRootInlineBox(); if (obj->isText()) { InlineTextBox* textBox = toRenderText(obj)->createInlineTextBox(); @@ -171,7 +142,7 @@ static bool parentIsConstructedOrHaveNext(InlineFlowBox* parentBox) return false; } -InlineFlowBox* RenderBlockFlow::createLineBoxes(RenderObject* obj, const LineInfo& lineInfo, InlineBox* childBox, bool startNewSegment) +InlineFlowBox* RenderBlockFlow::createLineBoxes(RenderObject* obj, const LineInfo& lineInfo, InlineBox* childBox) { // See if we have an unconstructed line box for this object that is also // the last item on the line. @@ -194,8 +165,7 @@ InlineFlowBox* RenderBlockFlow::createLineBoxes(RenderObject* obj, const LineInf // the same line (this can happen with very fancy language mixtures). bool constructedNewBox = false; bool allowedToConstructNewBox = !hasDefaultLineBoxContain || !inlineFlow || inlineFlow->alwaysCreateLineBoxes(); - bool mustCreateBoxesToRoot = startNewSegment && !(parentBox && parentBox->isRootInlineBox()); - bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox) && !mustCreateBoxesToRoot; + bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox); if (allowedToConstructNewBox && !canUseExistingParentBox) { // We need to make a new box for this render object. Once // made, we need to place it at the end of the current line. @@ -287,19 +257,17 @@ RootInlineBox* RenderBlockFlow::constructLine(BidiRunList<BidiRun>& bidiRuns, co if (!box) continue; - if (!rootHasSelectedChildren && box->renderer()->selectionState() != RenderObject::SelectionNone) + if (!rootHasSelectedChildren && box->renderer().selectionState() != RenderObject::SelectionNone) rootHasSelectedChildren = true; // If we have no parent box yet, or if the run is not simply a sibling, // then we need to construct inline boxes as necessary to properly enclose the // run's inline box. Segments can only be siblings at the root level, as // they are positioned separately. - bool runStartsSegment = r->m_startsSegment; - - if (!parentBox || parentBox->renderer() != r->m_object->parent() || runStartsSegment) + if (!parentBox || parentBox->renderer() != r->m_object->parent()) { // Create new inline boxes all the way back to the appropriate insertion point. - parentBox = createLineBoxes(r->m_object->parent(), lineInfo, box, runStartsSegment); - else { + parentBox = createLineBoxes(r->m_object->parent(), lineInfo, box); + } else { // Append the inline box to this line. parentBox->addToLine(box); } @@ -314,6 +282,9 @@ RootInlineBox* RenderBlockFlow::constructLine(BidiRunList<BidiRun>& bidiRuns, co text->setDirOverride(r->dirOverride(visuallyOrdered)); if (r->m_hasHyphen) text->setHasHyphen(true); + + if (AXObjectCache* cache = document().existingAXObjectCache()) + cache->inlineTextBoxesUpdated(r->m_object); } } @@ -324,7 +295,7 @@ RootInlineBox* RenderBlockFlow::constructLine(BidiRunList<BidiRun>& bidiRuns, co // Set the m_selectedChildren flag on the root inline box if one of the leaf inline box // from the bidi runs walk above has a selection state. if (rootHasSelectedChildren) - lastLineBox()->root()->setHasSelectedChildren(true); + lastLineBox()->root().setHasSelectedChildren(true); // Set bits on our inline flow boxes that indicate which sides should // paint borders/margins/padding. This knowledge will ultimately be used when @@ -466,11 +437,11 @@ static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* ru LayoutUnit hyphenWidth = 0; if (toInlineTextBox(run->m_box)->hasHyphen()) { const Font& font = renderer->style(lineInfo.isFirstLine())->font(); - hyphenWidth = measureHyphenWidth(renderer, font); + hyphenWidth = measureHyphenWidth(renderer, font, run->direction()); } float measuredWidth = 0; - bool kerningIsEnabled = font.typesettingFeatures() & Kerning; + bool kerningIsEnabled = font.fontDescription().typesettingFeatures() & Kerning; #if OS(MACOSX) // FIXME: Having any font feature settings enabled can lead to selection gaps on @@ -495,7 +466,7 @@ static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* ru lastEndOffset = wordMeasurement.endOffset; if (kerningIsEnabled && lastEndOffset == run->m_stop) { int wordLength = lastEndOffset - wordMeasurement.startOffset; - measuredWidth += renderer->width(wordMeasurement.startOffset, wordLength, xPos, lineInfo.isFirstLine()); + measuredWidth += renderer->width(wordMeasurement.startOffset, wordLength, xPos, run->direction(), lineInfo.isFirstLine()); if (i > 0 && wordLength == 1 && renderer->characterAt(wordMeasurement.startOffset) == ' ') measuredWidth += renderer->style()->wordSpacing(); } else @@ -514,19 +485,19 @@ static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* ru } if (!measuredWidth) - measuredWidth = renderer->width(run->m_start, run->m_stop - run->m_start, xPos, lineInfo.isFirstLine(), &fallbackFonts, &glyphOverflow); + measuredWidth = renderer->width(run->m_start, run->m_stop - run->m_start, xPos, run->direction(), lineInfo.isFirstLine(), &fallbackFonts, &glyphOverflow); run->m_box->setLogicalWidth(measuredWidth + hyphenWidth); if (!fallbackFonts.isEmpty()) { ASSERT(run->m_box->isText()); - GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(toInlineTextBox(run->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).iterator; + GlyphOverflowAndFallbackFontsMap::ValueType* it = textBoxDataMap.add(toInlineTextBox(run->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).storedValue; ASSERT(it->value.first.isEmpty()); copyToVector(fallbackFonts, it->value.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())).iterator; + GlyphOverflowAndFallbackFontsMap::ValueType* it = textBoxDataMap.add(toInlineTextBox(run->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).storedValue; it->value.second = glyphOverflow; run->m_box->clearKnownToHaveNoOverflow(); } @@ -539,9 +510,6 @@ static inline void computeExpansionForJustifiedText(BidiRun* firstRun, BidiRun* size_t i = 0; for (BidiRun* r = firstRun; r; r = r->next()) { - // This method is called once per segment, do not move past the current segment. - if (r->m_startsSegment) - break; if (!r->m_box || r == trailingSpaceRun) continue; @@ -550,8 +518,8 @@ static inline void computeExpansionForJustifiedText(BidiRun* firstRun, BidiRun* ASSERT(opportunitiesInRun <= expansionOpportunityCount); - // Only justify text if whitespace is collapsed. - if (r->m_object->style()->collapseWhiteSpace()) { + // Don't justify for white-space: pre. + if (r->m_object->style()->whiteSpace() != PRE) { InlineTextBox* textBox = toInlineTextBox(r->m_box); int expansion = (availableLogicalWidth - totalLogicalWidth) * opportunitiesInRun / expansionOpportunityCount; textBox->setExpansion(expansion); @@ -564,10 +532,10 @@ static inline void computeExpansionForJustifiedText(BidiRun* firstRun, BidiRun* } } -void RenderBlockFlow::updateLogicalWidthForAlignment(const ETextAlign& textAlign, const RootInlineBox* rootInlineBox, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float& availableLogicalWidth, int expansionOpportunityCount) +void RenderBlockFlow::updateLogicalWidthForAlignment(const ETextAlign& textAlign, const RootInlineBox* rootInlineBox, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float& availableLogicalWidth, unsigned expansionOpportunityCount) { TextDirection direction; - if (rootInlineBox && rootInlineBox->renderer()->style()->unicodeBidi() == Plaintext) + if (rootInlineBox && rootInlineBox->renderer().style()->unicodeBidi() == Plaintext) direction = rootInlineBox->direction(); else direction = style()->direction(); @@ -612,15 +580,15 @@ void RenderBlockFlow::updateLogicalWidthForAlignment(const ETextAlign& textAlign updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); break; } + if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) + logicalLeft += verticalScrollbarWidth(); } static void updateLogicalInlinePositions(RenderBlockFlow* block, float& lineLogicalLeft, float& lineLogicalRight, float& availableLogicalWidth, bool firstLine, IndentTextOrNot shouldIndentText, LayoutUnit boxLogicalHeight) { LayoutUnit lineLogicalHeight = block->minLineHeightForReplacedRenderer(firstLine, boxLogicalHeight); - lineLogicalLeft = block->logicalLeftOffsetForLine(block->logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight); - // FIXME: This shouldn't be pixel snapped once multicolumn layout has been updated to correctly carry over subpixel values. - // https://bugs.webkit.org/show_bug.cgi?id=105461 - lineLogicalRight = block->pixelSnappedLogicalRightOffsetForLine(block->logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight); + lineLogicalLeft = block->logicalLeftOffsetForLine(block->logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight).toFloat(); + lineLogicalRight = block->logicalRightOffsetForLine(block->logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight).toFloat(); availableLogicalWidth = lineLogicalRight - lineLogicalLeft; } @@ -633,7 +601,7 @@ void RenderBlockFlow::computeInlineDirectionPositionsForLine(RootInlineBox* line // box is only affected if it is the first child of its parent element." // CSS3 "text-indent", "each-line" affects the first line of the block container as well as each line after a forced line break, // but does not affect lines after a soft wrap break. - bool isFirstLine = lineInfo.isFirstLine() && !(isAnonymousBlock() && parent()->firstChild() != this); + bool isFirstLine = lineInfo.isFirstLine() && !(isAnonymousBlock() && parent()->slowFirstChild() != this); bool isAfterHardLineBreak = lineBox->prevRootBox() && lineBox->prevRootBox()->endsWithBreak(); IndentTextOrNot shouldIndentText = requiresIndent(isFirstLine, isAfterHardLineBreak, style()); float lineLogicalLeft; @@ -641,35 +609,6 @@ void RenderBlockFlow::computeInlineDirectionPositionsForLine(RootInlineBox* line float availableLogicalWidth; updateLogicalInlinePositions(this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, 0); bool needsWordSpacing; - ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo(); - if (shapeInsideInfo && shapeInsideInfo->hasSegments()) { - BidiRun* segmentStart = firstRun; - const SegmentList& segments = shapeInsideInfo->segments(); - float logicalLeft = max<float>(segments[0].logicalLeft, lineLogicalLeft); - float logicalRight = min<float>(segments[0].logicalRight, lineLogicalRight); - float startLogicalLeft = logicalLeft; - float endLogicalRight = logicalLeft; - float minLogicalLeft = logicalLeft; - float maxLogicalRight = logicalLeft; - lineBox->beginPlacingBoxRangesInInlineDirection(logicalLeft); - for (size_t i = 0; i < segments.size(); i++) { - if (i) { - logicalLeft = max<float>(segments[i].logicalLeft, lineLogicalLeft); - logicalRight = min<float>(segments[i].logicalRight, lineLogicalRight); - } - availableLogicalWidth = logicalRight - logicalLeft; - BidiRun* newSegmentStart = computeInlineDirectionPositionsForSegment(lineBox, lineInfo, textAlign, logicalLeft, availableLogicalWidth, segmentStart, trailingSpaceRun, textBoxDataMap, verticalPositionCache, wordMeasurements); - needsWordSpacing = false; - endLogicalRight = lineBox->placeBoxRangeInInlineDirection(segmentStart->m_box, newSegmentStart ? newSegmentStart->m_box : 0, logicalLeft, minLogicalLeft, maxLogicalRight, needsWordSpacing, textBoxDataMap); - if (!newSegmentStart || !newSegmentStart->next()) - break; - ASSERT(newSegmentStart->m_startsSegment); - // Discard the empty segment start marker bidi runs - segmentStart = newSegmentStart->next(); - } - lineBox->endPlacingBoxRangesInInlineDirection(startLogicalLeft, endLogicalRight, minLogicalLeft, maxLogicalRight); - return; - } if (firstRun && firstRun->m_object->isReplaced()) { RenderBox* renderBox = toRenderBox(firstRun->m_object); @@ -687,8 +626,8 @@ BidiRun* RenderBlockFlow::computeInlineDirectionPositionsForSegment(RootInlineBo float& availableLogicalWidth, BidiRun* firstRun, BidiRun* trailingSpaceRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements) { - bool needsWordSpacing = false; - float totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth(); + bool needsWordSpacing = true; + float totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth().toFloat(); unsigned expansionOpportunityCount = 0; bool isAfterExpansion = true; Vector<unsigned, 16> expansionOpportunities; @@ -697,10 +636,6 @@ BidiRun* RenderBlockFlow::computeInlineDirectionPositionsForSegment(RootInlineBo BidiRun* r = firstRun; for (; r; r = r->next()) { - // Once we have reached the start of the next segment, we have finished - // computing the positions for this segment's contents. - if (r->m_startsSegment) - break; if (!r->m_box || r->m_object->isOutOfFlowPositioned() || r->m_box->isLineBreak()) continue; // Positioned objects are only participating to figure out their // correct static x position. They have no effect on the width. @@ -712,17 +647,17 @@ BidiRun* RenderBlockFlow::computeInlineDirectionPositionsForSegment(RootInlineBo toInlineTextBox(r->m_box)->setCanHaveLeadingExpansion(true); unsigned opportunitiesInRun; if (rt->is8Bit()) - opportunitiesInRun = Font::expansionOpportunityCount(rt->characters8() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion); + opportunitiesInRun = Character::expansionOpportunityCount(rt->characters8() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion); else - opportunitiesInRun = Font::expansionOpportunityCount(rt->characters16() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion); + opportunitiesInRun = Character::expansionOpportunityCount(rt->characters16() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion); expansionOpportunities.append(opportunitiesInRun); expansionOpportunityCount += opportunitiesInRun; } - if (int length = rt->textLength()) { + if (rt->textLength()) { if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characterAt(r->m_start))) - totalLogicalWidth += rt->style(lineInfo.isFirstLine())->font().wordSpacing(); - needsWordSpacing = !isSpaceOrNewline(rt->characterAt(r->m_stop - 1)) && r->m_stop == length; + totalLogicalWidth += rt->style(lineInfo.isFirstLine())->font().fontDescription().wordSpacing(); + needsWordSpacing = !isSpaceOrNewline(rt->characterAt(r->m_stop - 1)); } setLogicalWidthForTextRun(lineBox, r, rt, totalLogicalWidth, lineInfo, textBoxDataMap, verticalPositionCache, wordMeasurements); @@ -732,7 +667,7 @@ BidiRun* RenderBlockFlow::computeInlineDirectionPositionsForSegment(RootInlineBo RenderBox* renderBox = toRenderBox(r->m_object); if (renderBox->isRubyRun()) setMarginsForRubyRun(r, toRenderRubyRun(renderBox), previousObject, lineInfo); - r->m_box->setLogicalWidth(logicalWidthForChild(renderBox)); + r->m_box->setLogicalWidth(logicalWidthForChild(renderBox).toFloat()); totalLogicalWidth += marginStartForChild(renderBox) + marginEndForChild(renderBox); } } @@ -767,7 +702,7 @@ void RenderBlockFlow::computeBlockDirectionPositionsForLine(RootInlineBox* lineB // Align positioned boxes with the top of the line box. This is // a reasonable approximation of an appropriate y position. if (r->m_object->isOutOfFlowPositioned()) - r->m_box->setLogicalTop(logicalHeight()); + r->m_box->setLogicalTop(logicalHeight().toFloat()); // Position is used to properly position both replaced elements and // to update the static normal flow x/y of positioned elements. @@ -776,83 +711,6 @@ void RenderBlockFlow::computeBlockDirectionPositionsForLine(RootInlineBox* lineB else if (r->m_object->isBox()) toRenderBox(r->m_object)->positionLineBox(r->m_box); } - // Positioned objects and zero-length text nodes destroy their boxes in - // position(), which unnecessarily dirties the line. - lineBox->markDirty(false); -} - -static inline bool isCollapsibleSpace(UChar character, RenderText* renderer) -{ - if (character == ' ' || character == '\t' || character == softHyphen) - return true; - if (character == '\n') - return !renderer->style()->preserveNewline(); - return false; -} - -template <typename CharacterType> -static inline int findFirstTrailingSpace(RenderText* lastText, const CharacterType* characters, int start, int stop) -{ - int firstSpace = stop; - while (firstSpace > start) { - UChar current = characters[firstSpace - 1]; - if (!isCollapsibleSpace(current, lastText)) - break; - firstSpace--; - } - - return firstSpace; -} - -inline BidiRun* RenderBlockFlow::handleTrailingSpaces(BidiRunList<BidiRun>& bidiRuns, BidiContext* currentContext) -{ - if (!bidiRuns.runCount() - || !bidiRuns.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace() - || !bidiRuns.logicallyLastRun()->m_object->style()->autoWrap()) - return 0; - - BidiRun* trailingSpaceRun = bidiRuns.logicallyLastRun(); - RenderObject* lastObject = trailingSpaceRun->m_object; - if (!lastObject->isText()) - return 0; - - RenderText* lastText = toRenderText(lastObject); - int firstSpace; - if (lastText->is8Bit()) - firstSpace = findFirstTrailingSpace(lastText, lastText->characters8(), trailingSpaceRun->start(), trailingSpaceRun->stop()); - else - firstSpace = findFirstTrailingSpace(lastText, lastText->characters16(), trailingSpaceRun->start(), trailingSpaceRun->stop()); - - if (firstSpace == trailingSpaceRun->stop()) - return 0; - - TextDirection direction = style()->direction(); - bool shouldReorder = trailingSpaceRun != (direction == LTR ? bidiRuns.lastRun() : bidiRuns.firstRun()); - if (firstSpace != trailingSpaceRun->start()) { - BidiContext* baseContext = currentContext; - while (BidiContext* parent = baseContext->parent()) - baseContext = parent; - - BidiRun* newTrailingRun = new BidiRun(firstSpace, trailingSpaceRun->m_stop, trailingSpaceRun->m_object, baseContext, OtherNeutral); - trailingSpaceRun->m_stop = firstSpace; - if (direction == LTR) - bidiRuns.addRun(newTrailingRun); - else - bidiRuns.prependRun(newTrailingRun); - trailingSpaceRun = newTrailingRun; - return trailingSpaceRun; - } - if (!shouldReorder) - return trailingSpaceRun; - - if (direction == LTR) { - bidiRuns.moveRunToEnd(trailingSpaceRun); - trailingSpaceRun->m_level = 0; - } else { - bidiRuns.moveRunToBeginning(trailingSpaceRun); - trailingSpaceRun->m_level = 1; - } - return trailingSpaceRun; } void RenderBlockFlow::appendFloatingObjectToLastLine(FloatingObject* floatingObject) @@ -891,14 +749,14 @@ static void restoreIsolatedMidpointStates(InlineBidiResolver& topResolver, Inlin } // FIXME: BidiResolver should have this logic. -static inline void constructBidiRunsForSegment(InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfRuns, VisualDirectionOverride override, bool previousLineBrokeCleanly, bool isNewUBAParagraph) +static inline void constructBidiRunsForLine(const RenderBlockFlow* block, InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfLine, VisualDirectionOverride override, bool previousLineBrokeCleanly, bool isNewUBAParagraph) { // FIXME: We should pass a BidiRunList into createBidiRunsForLine instead // of the resolver owning the runs. ASSERT(&topResolver.runs() == &bidiRuns); - ASSERT(topResolver.position() != endOfRuns); + ASSERT(topResolver.position() != endOfLine); RenderObject* currentRoot = topResolver.position().root(); - topResolver.createBidiRunsForLine(endOfRuns, override, previousLineBrokeCleanly); + topResolver.createBidiRunsForLine(endOfLine, override, previousLineBrokeCleanly); while (!topResolver.isolatedRuns().isEmpty()) { // It does not matter which order we resolve the runs as long as we resolve them all. @@ -919,7 +777,7 @@ static inline void constructBidiRunsForSegment(InlineBidiResolver& topResolver, LineMidpointState& isolatedLineMidpointState = isolatedResolver.midpointState(); isolatedLineMidpointState = topResolver.midpointStateForIsolatedRun(isolatedRun); EUnicodeBidi unicodeBidi = isolatedInline->style()->unicodeBidi(); - TextDirection direction = isolatedInline->style()->direction(); + TextDirection direction; if (unicodeBidi == Plaintext) { if (isNewUBAParagraph) direction = determinePlaintextDirectionality(isolatedInline, startObj); @@ -941,7 +799,7 @@ static inline void constructBidiRunsForSegment(InlineBidiResolver& topResolver, // We stop at the next end of line; we may re-enter this isolate in the next call to constructBidiRuns(). // FIXME: What should end and previousLineBrokeCleanly be? // rniwa says previousLineBrokeCleanly is just a WinIE hack and could always be false here? - isolatedResolver.createBidiRunsForLine(endOfRuns, NoVisualOverride, previousLineBrokeCleanly); + isolatedResolver.createBidiRunsForLine(endOfLine, NoVisualOverride, previousLineBrokeCleanly); ASSERT(isolatedResolver.runs().runCount()); if (isolatedResolver.runs().runCount()) @@ -950,49 +808,13 @@ static inline void constructBidiRunsForSegment(InlineBidiResolver& topResolver, // If we encountered any nested isolate runs, just move them // to the top resolver's list for later processing. if (!isolatedResolver.isolatedRuns().isEmpty()) { - topResolver.isolatedRuns().append(isolatedResolver.isolatedRuns()); + topResolver.isolatedRuns().appendVector(isolatedResolver.isolatedRuns()); currentRoot = isolatedInline; restoreIsolatedMidpointStates(topResolver, isolatedResolver); } } } -static inline bool segmentIsEmpty(const InlineIterator& segmentStart, const InlineIterator& segmentEnd) -{ - return segmentStart == segmentEnd; -} - -static inline void constructBidiRunsForLine(const RenderBlockFlow* block, InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfLine, VisualDirectionOverride override, bool previousLineBrokeCleanly, bool isNewUBAParagraph) -{ - ShapeInsideInfo* shapeInsideInfo = block->layoutShapeInsideInfo(); - if (!shapeInsideInfo || !shapeInsideInfo->hasSegments()) { - constructBidiRunsForSegment(topResolver, bidiRuns, endOfLine, override, previousLineBrokeCleanly, isNewUBAParagraph); - return; - } - - const SegmentRangeList& segmentRanges = shapeInsideInfo->segmentRanges(); - ASSERT(segmentRanges.size()); - - for (size_t i = 0; i < segmentRanges.size(); i++) { - LineSegmentIterator iterator = segmentRanges[i].start; - InlineIterator segmentStart(iterator.root, iterator.object, iterator.offset); - iterator = segmentRanges[i].end; - InlineIterator segmentEnd(iterator.root, iterator.object, iterator.offset); - if (i) { - ASSERT(segmentStart.object()); - BidiRun* segmentMarker = createRun(segmentStart.m_pos, segmentStart.m_pos, segmentStart.object(), topResolver); - segmentMarker->m_startsSegment = true; - bidiRuns.addRun(segmentMarker); - // Do not collapse midpoints between segments - topResolver.midpointState().betweenMidpoints = false; - } - if (!segmentIsEmpty(segmentStart, segmentEnd)) { - topResolver.setPosition(segmentStart, numberOfIsolateAncestors(segmentStart)); - constructBidiRunsForSegment(topResolver, bidiRuns, segmentEnd, override, previousLineBrokeCleanly, isNewUBAParagraph); - } - } -} - // This function constructs line boxes for all of the text runs in the resolver and computes their position. RootInlineBox* RenderBlockFlow::createLineBoxesFromBidiRuns(unsigned bidiLevel, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& end, LineInfo& lineInfo, VerticalPositionCache& verticalPositionCache, BidiRun* trailingSpaceRun, WordMeasurements& wordMeasurements) { @@ -1036,95 +858,6 @@ RootInlineBox* RenderBlockFlow::createLineBoxesFromBidiRuns(unsigned bidiLevel, return lineBox; } -// Like LayoutState for layout(), LineLayoutState keeps track of global information -// during an entire linebox tree layout pass (aka layoutInlineChildren). -class LineLayoutState { -public: - LineLayoutState(bool fullLayout, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom, RenderFlowThread* flowThread) - : m_lastFloat(0) - , m_endLine(0) - , m_floatIndex(0) - , m_endLineLogicalTop(0) - , m_endLineMatched(false) - , m_checkForFloatsFromLastLine(false) - , m_isFullLayout(fullLayout) - , m_repaintLogicalTop(repaintLogicalTop) - , m_repaintLogicalBottom(repaintLogicalBottom) - , m_adjustedLogicalLineTop(0) - , m_usesRepaintBounds(false) - , m_flowThread(flowThread) - { } - - void markForFullLayout() { m_isFullLayout = true; } - bool isFullLayout() const { return m_isFullLayout; } - - bool usesRepaintBounds() const { return m_usesRepaintBounds; } - - void setRepaintRange(LayoutUnit logicalHeight) - { - m_usesRepaintBounds = true; - m_repaintLogicalTop = m_repaintLogicalBottom = logicalHeight; - } - - void updateRepaintRangeFromBox(RootInlineBox* box, LayoutUnit paginationDelta = 0) - { - m_usesRepaintBounds = true; - m_repaintLogicalTop = min(m_repaintLogicalTop, box->logicalTopVisualOverflow() + min<LayoutUnit>(paginationDelta, 0)); - m_repaintLogicalBottom = max(m_repaintLogicalBottom, box->logicalBottomVisualOverflow() + max<LayoutUnit>(paginationDelta, 0)); - } - - bool endLineMatched() const { return m_endLineMatched; } - void setEndLineMatched(bool endLineMatched) { m_endLineMatched = endLineMatched; } - - bool checkForFloatsFromLastLine() const { return m_checkForFloatsFromLastLine; } - void setCheckForFloatsFromLastLine(bool check) { m_checkForFloatsFromLastLine = check; } - - LineInfo& lineInfo() { return m_lineInfo; } - const LineInfo& lineInfo() const { return m_lineInfo; } - - 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; } - - FloatingObject* lastFloat() const { return m_lastFloat; } - void setLastFloat(FloatingObject* lastFloat) { m_lastFloat = lastFloat; } - - Vector<RenderBlockFlow::FloatWithRect>& floats() { return m_floats; } - - unsigned floatIndex() const { return m_floatIndex; } - void setFloatIndex(unsigned floatIndex) { m_floatIndex = floatIndex; } - - LayoutUnit adjustedLogicalLineTop() const { return m_adjustedLogicalLineTop; } - void setAdjustedLogicalLineTop(LayoutUnit value) { m_adjustedLogicalLineTop = value; } - - RenderFlowThread* flowThread() const { return m_flowThread; } - void setFlowThread(RenderFlowThread* thread) { m_flowThread = thread; } - -private: - Vector<RenderBlockFlow::FloatWithRect> m_floats; - FloatingObject* m_lastFloat; - RootInlineBox* m_endLine; - LineInfo m_lineInfo; - unsigned m_floatIndex; - LayoutUnit m_endLineLogicalTop; - bool m_endLineMatched; - bool m_checkForFloatsFromLastLine; - - bool m_isFullLayout; - - // FIXME: Should this be a range object instead of two ints? - LayoutUnit& m_repaintLogicalTop; - LayoutUnit& m_repaintLogicalBottom; - - LayoutUnit m_adjustedLogicalLineTop; - - bool m_usesRepaintBounds; - - RenderFlowThread* m_flowThread; -}; - static void deleteLineRange(LineLayoutState& layoutState, RootInlineBox* startLine, RootInlineBox* stopLine = 0) { RootInlineBox* boxToDelete = startLine; @@ -1138,7 +871,7 @@ static void deleteLineRange(LineLayoutState& layoutState, RootInlineBox* startLi } } -void RenderBlockFlow::layoutRunsAndFloats(LineLayoutState& layoutState, bool hasInlineChild) +void RenderBlockFlow::layoutRunsAndFloats(LineLayoutState& layoutState) { // We want to skip ahead to the first dirty line InlineBidiResolver resolver; @@ -1150,30 +883,8 @@ void RenderBlockFlow::layoutRunsAndFloats(LineLayoutState& layoutState, bool has consecutiveHyphenatedLines++; } - // FIXME: This would make more sense outside of this function, but since - // 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()) { - // Mark as needing a full layout to force us to repaint. Allow regions - // to reflow as needed. - setNeedsLayout(MarkOnlyThis); - - if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) { - setShouldDoFullRepaintAfterLayout(true); - } else { - RenderView* v = view(); - if (v && !v->doingFullRepaint() && hasLayer()) { - // Because we waited until we were already inside layout to discover - // that the block really needed a full layout, we missed our chance to repaint the layer - // before layout started. Luckily the layer has cached the repaint rect for its original - // position and size, and so we can use that to make a repaint happen now. - repaintUsingContainer(containerForRepaint(), pixelSnappedIntRect(layer()->repainter().repaintRect())); - } - } - } - if (containsFloats()) - layoutState.setLastFloat(m_floatingObjects->set().last()); + layoutState.setLastFloat(m_floatingObjects->set().last().get()); // We also find the first clean line and extract these lines. We will add them back // if we determine that we're able to synchronize after handling all our dirty lines. @@ -1193,9 +904,9 @@ void RenderBlockFlow::layoutRunsAndFloats(LineLayoutState& layoutState, bool has // adjust the height accordingly. // A line break can be either the first or the last object on a line, depending on its direction. if (InlineBox* lastLeafChild = lastRootBox()->lastLeafChild()) { - RenderObject* lastObject = lastLeafChild->renderer(); + RenderObject* lastObject = &lastLeafChild->renderer(); if (!lastObject->isBR()) - lastObject = lastRootBox()->firstLeafChild()->renderer(); + lastObject = &lastRootBox()->firstLeafChild()->renderer(); if (lastObject->isBR()) { EClear clear = lastObject->style()->clear(); if (clear != CNONE) @@ -1209,16 +920,6 @@ void RenderBlockFlow::layoutRunsAndFloats(LineLayoutState& layoutState, bool has repaintDirtyFloats(layoutState.floats()); } -RenderTextInfo::RenderTextInfo() - : m_text(0) - , m_font(0) -{ -} - -RenderTextInfo::~RenderTextInfo() -{ -} - // Before restarting the layout loop with a new logicalHeight, remove all floats that were added and reset the resolver. inline const InlineIterator& RenderBlockFlow::restartLayoutRunsAndFloatsInRange(LayoutUnit oldLogicalHeight, LayoutUnit newLogicalHeight, FloatingObject* lastFloatFromPreviousLine, InlineBidiResolver& resolver, const InlineIterator& oldEnd) { @@ -1228,161 +929,6 @@ inline const InlineIterator& RenderBlockFlow::restartLayoutRunsAndFloatsInRange( return oldEnd; } -static inline LayoutUnit adjustLogicalLineTop(ShapeInsideInfo* shapeInsideInfo, InlineIterator start, InlineIterator end, const WordMeasurements& wordMeasurements) -{ - if (!shapeInsideInfo || end != start) - return 0; - - float minWidth = firstPositiveWidth(wordMeasurements); - ASSERT(minWidth || wordMeasurements.isEmpty()); - if (minWidth > 0 && shapeInsideInfo->adjustLogicalLineTop(minWidth)) - return shapeInsideInfo->logicalLineTop(); - - return shapeInsideInfo->shapeLogicalBottom(); -} - -static inline void pushShapeContentOverflowBelowTheContentBox(RenderBlockFlow* block, ShapeInsideInfo* shapeInsideInfo, LayoutUnit lineTop, LayoutUnit lineHeight) -{ - ASSERT(shapeInsideInfo); - - LayoutUnit logicalLineBottom = lineTop + lineHeight; - LayoutUnit shapeLogicalBottom = shapeInsideInfo->shapeLogicalBottom(); - LayoutUnit shapeContainingBlockHeight = shapeInsideInfo->shapeContainingBlockHeight(); - - bool isOverflowPositionedAlready = (shapeContainingBlockHeight - shapeInsideInfo->owner()->borderAndPaddingAfter() + lineHeight) <= lineTop; - - // If the last line overlaps with the shape, we don't need the segments anymore - if (lineTop < shapeLogicalBottom && shapeLogicalBottom < logicalLineBottom) - shapeInsideInfo->clearSegments(); - if (logicalLineBottom <= shapeLogicalBottom || !shapeContainingBlockHeight || isOverflowPositionedAlready) - return; - - LayoutUnit newLogicalHeight = block->logicalHeight() + (shapeContainingBlockHeight - (lineTop + shapeInsideInfo->owner()->borderAndPaddingAfter())); - block->setLogicalHeight(newLogicalHeight); -} - -void RenderBlockFlow::updateShapeAndSegmentsForCurrentLine(ShapeInsideInfo*& shapeInsideInfo, const LayoutSize& logicalOffsetFromShapeContainer, LineLayoutState& layoutState) -{ - if (layoutState.flowThread()) - return updateShapeAndSegmentsForCurrentLineInFlowThread(shapeInsideInfo, layoutState); - - if (!shapeInsideInfo) - return; - - LayoutUnit lineTop = logicalHeight() + logicalOffsetFromShapeContainer.height(); - LayoutUnit lineLeft = logicalOffsetFromShapeContainer.width(); - LayoutUnit lineHeight = this->lineHeight(layoutState.lineInfo().isFirstLine(), isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); - - // FIXME: Bug 95361: It is possible for a line to grow beyond lineHeight, in which case these segments may be incorrect. - shapeInsideInfo->updateSegmentsForLine(LayoutSize(lineLeft, lineTop), lineHeight); - - pushShapeContentOverflowBelowTheContentBox(this, shapeInsideInfo, lineTop, lineHeight); -} - -void RenderBlockFlow::updateShapeAndSegmentsForCurrentLineInFlowThread(ShapeInsideInfo*& shapeInsideInfo, LineLayoutState& layoutState) -{ - ASSERT(layoutState.flowThread()); - - RenderRegion* currentRegion = regionAtBlockOffset(logicalHeight()); - if (!currentRegion || !currentRegion->logicalHeight()) - return; - - shapeInsideInfo = currentRegion->shapeInsideInfo(); - - RenderRegion* nextRegion = 0; - if (!currentRegion->isLastRegion()) { - RenderRegionList regionList = layoutState.flowThread()->renderRegionList(); - RenderRegionList::const_iterator it = regionList.find(currentRegion); - nextRegion = *(++it); - } - - // We only want to deal regions with shapes, so we check if the next region has a shape - if (!shapeInsideInfo && nextRegion && !nextRegion->shapeInsideInfo()) - return; - - LayoutUnit lineHeight = this->lineHeight(layoutState.lineInfo().isFirstLine(), isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); - LayoutUnit logicalLineTopInFlowThread = logicalHeight() + offsetFromLogicalTopOfFirstPage(); - LayoutUnit logicalLineBottomInFlowThread = logicalLineTopInFlowThread + lineHeight; - LayoutUnit logicalRegionTopInFlowThread = currentRegion->logicalTopForFlowThreadContent(); - LayoutUnit logicalRegionBottomInFlowThread = logicalRegionTopInFlowThread + currentRegion->logicalHeight() - currentRegion->borderAndPaddingBefore() - currentRegion->borderAndPaddingAfter(); - - LayoutUnit shapeBottomInFlowThread = LayoutUnit::max(); - if (shapeInsideInfo) - shapeBottomInFlowThread = shapeInsideInfo->shapeLogicalBottom() + currentRegion->logicalTopForFlowThreadContent(); - - bool lineOverLapsWithShapeBottom = shapeBottomInFlowThread < logicalLineBottomInFlowThread; - bool lineOverLapsWithRegionBottom = logicalLineBottomInFlowThread > logicalRegionBottomInFlowThread; - bool overFlowsToNextRegion = nextRegion && (lineOverLapsWithShapeBottom || lineOverLapsWithRegionBottom); - - // If the line is between two shapes/regions we position the line to the top of the next shape/region - if (overFlowsToNextRegion) { - ASSERT(currentRegion != nextRegion); - LayoutUnit deltaToNextRegion = logicalRegionBottomInFlowThread - logicalLineTopInFlowThread; - setLogicalHeight(logicalHeight() + deltaToNextRegion); - - currentRegion = nextRegion; - shapeInsideInfo = currentRegion->shapeInsideInfo(); - - logicalLineTopInFlowThread = logicalHeight() + offsetFromLogicalTopOfFirstPage(); - logicalLineBottomInFlowThread = logicalLineTopInFlowThread + lineHeight; - logicalRegionTopInFlowThread = currentRegion->logicalTopForFlowThreadContent(); - logicalRegionBottomInFlowThread = logicalRegionTopInFlowThread + currentRegion->logicalHeight() - currentRegion->borderAndPaddingBefore() - currentRegion->borderAndPaddingAfter(); - } - - if (!shapeInsideInfo) - return; - - bool isFirstLineInRegion = logicalLineBottomInFlowThread <= (logicalRegionTopInFlowThread + lineHeight); - bool isFirstLineAdjusted = (logicalLineTopInFlowThread - logicalRegionTopInFlowThread) < (layoutState.adjustedLogicalLineTop() - currentRegion->borderAndPaddingBefore()); - // We position the first line to the top of the shape in the region or to the previously adjusted position in the shape - if (isFirstLineInRegion || isFirstLineAdjusted) { - LayoutUnit shapeTopOffset = layoutState.adjustedLogicalLineTop(); - if (!shapeTopOffset && (shapeInsideInfo->shapeLogicalTop() > 0)) - shapeTopOffset = shapeInsideInfo->shapeLogicalTop(); - - LayoutUnit shapePositionInFlowThread = currentRegion->logicalTopForFlowThreadContent() + shapeTopOffset; - LayoutUnit shapeTopLineTopDelta = shapePositionInFlowThread - logicalLineTopInFlowThread - currentRegion->borderAndPaddingBefore(); - - setLogicalHeight(logicalHeight() + shapeTopLineTopDelta); - logicalLineTopInFlowThread += shapeTopLineTopDelta; - layoutState.setAdjustedLogicalLineTop(0); - } - - LayoutUnit lineTop = logicalLineTopInFlowThread - currentRegion->logicalTopForFlowThreadContent() + currentRegion->borderAndPaddingBefore(); - // FIXME: Shape inside on a region does not yet take into account its padding for nested flow blocks - shapeInsideInfo->updateSegmentsForLine(LayoutSize(0, lineTop), lineHeight); - - if (currentRegion->isLastRegion()) - pushShapeContentOverflowBelowTheContentBox(this, shapeInsideInfo, lineTop, lineHeight); -} - -bool RenderBlockFlow::adjustLogicalLineTopAndLogicalHeightIfNeeded(ShapeInsideInfo* shapeInsideInfo, LayoutUnit absoluteLogicalTop, LineLayoutState& layoutState, InlineBidiResolver& resolver, FloatingObject* lastFloatFromPreviousLine, InlineIterator& end, WordMeasurements& wordMeasurements) -{ - LayoutUnit adjustedLogicalLineTop = adjustLogicalLineTop(shapeInsideInfo, resolver.position(), end, wordMeasurements); - - if (shapeInsideInfo && containsFloats()) { - lastFloatFromPreviousLine = m_floatingObjects->set().last(); - if (!wordMeasurements.size()) { - LayoutUnit floatLogicalTopOffset = shapeInsideInfo->computeFirstFitPositionForFloat(logicalSizeForFloat(lastFloatFromPreviousLine)); - if (logicalHeight() < floatLogicalTopOffset) - adjustedLogicalLineTop = floatLogicalTopOffset; - } - } - - if (!adjustedLogicalLineTop) - return false; - - LayoutUnit newLogicalHeight = adjustedLogicalLineTop - absoluteLogicalTop; - - if (layoutState.flowThread()) { - layoutState.setAdjustedLogicalLineTop(adjustedLogicalLineTop); - newLogicalHeight = logicalHeight(); - } - - end = restartLayoutRunsAndFloatsInRange(logicalHeight(), newLogicalHeight, lastFloatFromPreviousLine, resolver, end); - return true; -} - void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, InlineBidiResolver& resolver, const InlineIterator& cleanLineStart, const BidiStatus& cleanLineBidiStatus, unsigned consecutiveHyphenatedLines) { RenderStyle* styleToUse = style(); @@ -1396,22 +942,6 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I LineBreaker lineBreaker(this); LayoutSize logicalOffsetFromShapeContainer; - ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo(); - if (shapeInsideInfo) { - ASSERT(shapeInsideInfo->owner() == this || allowsShapeInsideInfoSharing(shapeInsideInfo->owner())); - if (shapeInsideInfo != this->shapeInsideInfo()) { - // FIXME Bug 100284: If subsequent LayoutStates are pushed, we will have to add - // their offsets from the original shape-inside container. - logicalOffsetFromShapeContainer = logicalOffsetFromShapeAncestorContainer(shapeInsideInfo->owner()); - } - // Begin layout at the logical top of our shape inside. - if (logicalHeight() + logicalOffsetFromShapeContainer.height() < shapeInsideInfo->shapeLogicalTop()) { - LayoutUnit logicalHeight = shapeInsideInfo->shapeLogicalTop() - logicalOffsetFromShapeContainer.height(); - if (layoutState.flowThread()) - logicalHeight -= shapeInsideInfo->owner()->borderAndPaddingBefore(); - setLogicalHeight(logicalHeight); - } - } while (!endOfLine.atEnd()) { // FIXME: Is this check necessary before the first iteration or can it be moved to the end? @@ -1430,9 +960,7 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I const InlineIterator previousEndofLine = endOfLine; bool isNewUBAParagraph = layoutState.lineInfo().previousLineBrokeCleanly(); - FloatingObject* lastFloatFromPreviousLine = (containsFloats()) ? m_floatingObjects->set().last() : 0; - - updateShapeAndSegmentsForCurrentLine(shapeInsideInfo, logicalOffsetFromShapeContainer, layoutState); + FloatingObject* lastFloatFromPreviousLine = (containsFloats()) ? m_floatingObjects->set().last().get() : 0; WordMeasurements wordMeasurements; endOfLine = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements); @@ -1447,18 +975,14 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I break; } - if (adjustLogicalLineTopAndLogicalHeightIfNeeded(shapeInsideInfo, logicalOffsetFromShapeContainer.height(), layoutState, resolver, lastFloatFromPreviousLine, endOfLine, wordMeasurements)) - continue; - ASSERT(endOfLine != resolver.position()); // This is a short-cut for empty lines. if (layoutState.lineInfo().isEmpty()) { if (lastRootBox()) - lastRootBox()->setLineBreakInfo(endOfLine.object(), endOfLine.m_pos, resolver.status()); + lastRootBox()->setLineBreakInfo(endOfLine.object(), endOfLine.offset(), resolver.status()); } else { VisualDirectionOverride override = (styleToUse->rtlOrdering() == VisualOrder ? (styleToUse->direction() == LTR ? VisualLeftToRightOverride : VisualRightToLeftOverride) : NoVisualOverride); - if (isNewUBAParagraph && styleToUse->unicodeBidi() == Plaintext && !resolver.context()->parent()) { TextDirection direction = determinePlaintextDirectionality(resolver.position().root(), resolver.position().object(), resolver.position().offset()); resolver.setStatus(BidiStatus(direction, isOverride(styleToUse->unicodeBidi()))); @@ -1468,7 +992,7 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I constructBidiRunsForLine(this, resolver, bidiRuns, endOfLine, override, layoutState.lineInfo().previousLineBrokeCleanly(), isNewUBAParagraph); ASSERT(resolver.position() == endOfLine); - BidiRun* trailingSpaceRun = !layoutState.lineInfo().previousLineBrokeCleanly() ? handleTrailingSpaces(bidiRuns, resolver.context()) : 0; + BidiRun* trailingSpaceRun = resolver.trailingSpaceRun(); if (bidiRuns.runCount() && lineBreaker.lineWasHyphenated()) { bidiRuns.logicallyLastRun()->m_hasHyphen = true; @@ -1487,7 +1011,7 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed). if (lineBox) { - lineBox->setLineBreakInfo(endOfLine.object(), endOfLine.m_pos, resolver.status()); + lineBox->setLineBreakInfo(endOfLine.object(), endOfLine.offset(), resolver.status()); if (layoutState.usesRepaintBounds()) layoutState.updateRepaintRangeFromBox(lineBox); @@ -1496,7 +1020,7 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I adjustLinePositionForPagination(lineBox, adjustment, layoutState.flowThread()); if (adjustment) { LayoutUnit oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, layoutState.lineInfo().isFirstLine()); - lineBox->adjustBlockDirectionPosition(adjustment); + lineBox->adjustBlockDirectionPosition(adjustment.toFloat()); if (layoutState.usesRepaintBounds()) layoutState.updateRepaintRangeFromBox(lineBox); @@ -1509,9 +1033,6 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I setLogicalHeight(lineBox->lineBottomWithLeading()); } - - if (layoutState.flowThread()) - updateRegionForLine(lineBox); } } } @@ -1535,7 +1056,7 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I it = lastFloatIterator; } for (; it != end; ++it) { - FloatingObject* f = *it; + FloatingObject* f = it->get(); appendFloatingObjectToLastLine(f); ASSERT(f->renderer() == layoutState.floats()[layoutState.floatIndex()].object); // If a float's geometry has changed, give up on syncing with clean lines. @@ -1543,7 +1064,7 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I checkForEndLineMatch = false; layoutState.setFloatIndex(layoutState.floatIndex() + 1); } - layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last() : 0); + layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last().get() : 0); } lineMidpointState.reset(); @@ -1628,10 +1149,8 @@ void RenderBlockFlow::linkToEndLineIfNeeded(LineLayoutState& layoutState) } if (delta) { layoutState.updateRepaintRangeFromBox(line, delta); - line->adjustBlockDirectionPosition(delta); + line->adjustBlockDirectionPosition(delta.toFloat()); } - if (layoutState.flowThread()) - updateRegionForLine(line); if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) { Vector<RenderBox*>::iterator end = cleanLineFloats->end(); for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) { @@ -1657,7 +1176,7 @@ void RenderBlockFlow::linkToEndLineIfNeeded(LineLayoutState& layoutState) if (layoutState.checkForFloatsFromLastLine()) { LayoutUnit bottomVisualOverflow = lastRootBox()->logicalBottomVisualOverflow(); LayoutUnit bottomLayoutOverflow = lastRootBox()->logicalBottomLayoutOverflow(); - TrailingFloatsRootInlineBox* trailingFloatsLineBox = new TrailingFloatsRootInlineBox(this); + TrailingFloatsRootInlineBox* trailingFloatsLineBox = new TrailingFloatsRootInlineBox(*this); m_lineBoxes.appendLineBox(trailingFloatsLineBox); trailingFloatsLineBox->setConstructed(); GlyphOverflowAndFallbackFontsMap textBoxDataMap; @@ -1665,12 +1184,10 @@ void RenderBlockFlow::linkToEndLineIfNeeded(LineLayoutState& layoutState) LayoutUnit blockLogicalHeight = logicalHeight(); trailingFloatsLineBox->alignBoxesInBlockDirection(blockLogicalHeight, textBoxDataMap, verticalPositionCache); trailingFloatsLineBox->setLineTopBottomPositions(blockLogicalHeight, blockLogicalHeight, blockLogicalHeight, blockLogicalHeight); - trailingFloatsLineBox->setPaginatedLineWidth(availableLogicalWidthForContent(blockLogicalHeight)); + trailingFloatsLineBox->setPaginatedLineWidth(availableLogicalWidthForContent()); LayoutRect logicalLayoutOverflow(0, blockLogicalHeight, 1, bottomLayoutOverflow - blockLogicalHeight); LayoutRect logicalVisualOverflow(0, blockLogicalHeight, 1, bottomVisualOverflow - blockLogicalHeight); trailingFloatsLineBox->setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, trailingFloatsLineBox->lineTop(), trailingFloatsLineBox->lineBottom()); - if (layoutState.flowThread()) - updateRegionForLine(trailingFloatsLineBox); } const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); @@ -1683,42 +1200,460 @@ void RenderBlockFlow::linkToEndLineIfNeeded(LineLayoutState& layoutState) it = lastFloatIterator; } for (; it != end; ++it) - appendFloatingObjectToLastLine(*it); - layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last() : 0); + appendFloatingObjectToLastLine(it->get()); + layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last().get() : 0); } } void RenderBlockFlow::repaintDirtyFloats(Vector<FloatWithRect>& floats) { size_t floatCount = floats.size(); - // Floats that did not have layout did not repaint when we laid them out. They would have + // Floats that did not have layout did not paint invalidations when we laid them out. They would have // painted by now if they had moved, but if they stayed at (0, 0), they still need to be // painted. for (size_t i = 0; i < floatCount; ++i) { if (!floats[i].everHadLayout) { RenderBox* f = floats[i].object; - if (!f->x() && !f->y() && f->checkForRepaintDuringLayout()) { + if (!f->x() && !f->y() && f->checkForPaintInvalidation()) { if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) - f->setShouldDoFullRepaintAfterLayout(true); + f->setShouldDoFullPaintInvalidationAfterLayout(true); else - f->repaint(); + f->paintInvalidationForWholeRenderer(); } } } } -void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom) +struct InlineMinMaxIterator { +/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to + inline min/max width calculations. Note the following about the way it walks: + (1) Positioned content is skipped (since it does not contribute to min/max width of a block) + (2) We do not drill into the children of floats or replaced elements, since you can't break + in the middle of such an element. + (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have + distinct borders/margin/padding that contribute to the min/max width. +*/ + RenderObject* parent; + RenderObject* current; + bool endOfInline; + + InlineMinMaxIterator(RenderObject* p, bool end = false) + : parent(p), current(p), endOfInline(end) + { + + } + + RenderObject* next(); +}; + +RenderObject* InlineMinMaxIterator::next() { - FastTextAutosizer* textAutosizer = document().fastTextAutosizer(); - if (textAutosizer) - textAutosizer->inflate(this); + RenderObject* result = 0; + bool oldEndOfInline = endOfInline; + endOfInline = false; + while (current || current == parent) { + if (!oldEndOfInline && (current == parent || (!current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned()))) + result = current->slowFirstChild(); + + if (!result) { + // We hit the end of our inline. (It was empty, e.g., <span></span>.) + if (!oldEndOfInline && current->isRenderInline()) { + result = current; + endOfInline = true; + break; + } - setLogicalHeight(borderBefore() + paddingBefore()); + while (current && current != parent) { + result = current->nextSibling(); + if (result) + break; + current = current->parent(); + if (current && current != parent && current->isRenderInline()) { + result = current; + endOfInline = true; + break; + } + } + } + + if (!result) + break; - // Lay out our hypothetical grid line as though it occurs at the top of the block. - if (view()->layoutState() && view()->layoutState()->lineGrid() == this) - layoutLineGridBox(); + if (!result->isOutOfFlowPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline())) + break; + current = result; + result = 0; + } + + // Update our position. + current = result; + return current; +} + +static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit) +{ + if (cssUnit.type() != Auto) + return (cssUnit.isFixed() ? static_cast<LayoutUnit>(cssUnit.value()) : childValue); + return 0; +} + +static LayoutUnit getBorderPaddingMargin(RenderBoxModelObject* child, bool endOfInline) +{ + RenderStyle* childStyle = child->style(); + if (endOfInline) { + return getBPMWidth(child->marginEnd(), childStyle->marginEnd()) + + getBPMWidth(child->paddingEnd(), childStyle->paddingEnd()) + + child->borderEnd(); + } + return getBPMWidth(child->marginStart(), childStyle->marginStart()) + + getBPMWidth(child->paddingStart(), childStyle->paddingStart()) + + child->borderStart(); +} + +static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild) +{ + if (trailingSpaceChild && trailingSpaceChild->isText()) { + // Collapse away the trailing space at the end of a block. + RenderText* t = toRenderText(trailingSpaceChild); + const UChar space = ' '; + const Font& font = t->style()->font(); // FIXME: This ignores first-line. + float spaceWidth = font.width(RenderBlockFlow::constructTextRun(t, font, &space, 1, t->style(), LTR)); + inlineMax -= spaceWidth + font.fontDescription().wordSpacing(); + if (inlineMin > inlineMax) + inlineMin = inlineMax; + } +} + +static inline void updatePreferredWidth(LayoutUnit& preferredWidth, float& result) +{ + LayoutUnit snappedResult = LayoutUnit::fromFloatCeil(result); + preferredWidth = max(snappedResult, preferredWidth); +} + +// When converting between floating point and LayoutUnits we risk losing precision +// with each conversion. When this occurs while accumulating our preferred widths, +// we can wind up with a line width that's larger than our maxPreferredWidth due to +// pure float accumulation. +static inline LayoutUnit adjustFloatForSubPixelLayout(float value) +{ + return LayoutUnit::fromFloatCeil(value); +} + +// FIXME: This function should be broken into something less monolithic. +// FIXME: The main loop here is very similar to LineBreaker::nextSegmentBreak. They can probably reuse code. +void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) +{ + float inlineMax = 0; + float inlineMin = 0; + + RenderStyle* styleToUse = style(); + RenderBlock* containingBlock = this->containingBlock(); + LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit(); + + // 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. + bool stripFrontSpaces = true; + RenderObject* trailingSpaceChild = 0; + + // Firefox and Opera will allow a table cell to grow to fit an image inside it under + // very specific cirucumstances (in order to match common WinIE renderings). + // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.) + bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse->logicalWidth().isIntrinsicOrAuto(); + + bool autoWrap, oldAutoWrap; + autoWrap = oldAutoWrap = styleToUse->autoWrap(); + + InlineMinMaxIterator childIterator(this); + + // Only gets added to the max preffered width once. + bool addedTextIndent = false; + // Signals the text indent was more negative than the min preferred width + bool hasRemainingNegativeTextIndent = false; + + LayoutUnit textIndent = minimumValueForLength(styleToUse->textIndent(), cw); + RenderObject* prevFloat = 0; + bool isPrevChildInlineFlow = false; + bool shouldBreakLineAfterText = false; + while (RenderObject* child = childIterator.next()) { + autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() : + child->style()->autoWrap(); + + if (!child->isBR()) { + // Step One: determine whether or not we need to go ahead and + // terminate our current line. Each discrete chunk can become + // the new min-width, if it is the widest chunk seen so far, and + // it can also become the max-width. + + // Children fall into three categories: + // (1) An inline flow object. These objects always have a min/max of 0, + // and are included in the iteration solely so that their margins can + // be added in. + // + // (2) An inline non-text non-flow object, e.g., an inline replaced element. + // These objects can always be on a line by themselves, so in this situation + // we need to go ahead and break the current line, and then add in our own + // margins and min/max width on its own line, and then terminate the line. + // + // (3) A text object. Text runs can have breakable characters at the start, + // the middle or the end. They may also lose whitespace off the front if + // we're already ignoring whitespace. In order to compute accurate min-width + // information, we need three pieces of information. + // (a) the min-width of the first non-breakable run. Should be 0 if the text string + // starts with whitespace. + // (b) the min-width of the last non-breakable run. Should be 0 if the text string + // ends with whitespace. + // (c) the min/max width of the string (trimmed for whitespace). + // + // If the text string starts with whitespace, then we need to go ahead and + // terminate our current line (unless we're already in a whitespace stripping + // mode. + // + // If the text string has a breakable character in the middle, but didn't start + // with whitespace, then we add the width of the first non-breakable run and + // then end the current line. We then need to use the intermediate min/max width + // values (if any of them are larger than our current min/max). We then look at + // the width of the last non-breakable run and use that to start a new line + // (unless we end in whitespace). + RenderStyle* childStyle = child->style(); + float childMin = 0; + float childMax = 0; + + if (!child->isText()) { + // Case (1) and (2). Inline replaced and inline flow elements. + if (child->isRenderInline()) { + // Add in padding/border/margin from the appropriate side of + // the element. + float bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline).toFloat(); + childMin += bpm; + childMax += bpm; + + inlineMin += childMin; + inlineMax += childMax; + + child->clearPreferredLogicalWidthsDirty(); + } else { + // Inline replaced elts add in their margins to their min/max values. + LayoutUnit margins = 0; + Length startMargin = childStyle->marginStart(); + Length endMargin = childStyle->marginEnd(); + if (startMargin.isFixed()) + margins += adjustFloatForSubPixelLayout(startMargin.value()); + if (endMargin.isFixed()) + margins += adjustFloatForSubPixelLayout(endMargin.value()); + childMin += margins.ceilToFloat(); + childMax += margins.ceilToFloat(); + } + } + + if (!child->isRenderInline() && !child->isText()) { + // Case (2). Inline replaced elements and floats. + // Go ahead and terminate the current line as far as + // minwidth is concerned. + LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth; + if (child->isBox() && child->isHorizontalWritingMode() != isHorizontalWritingMode()) { + RenderBox* childBox = toRenderBox(child); + LogicalExtentComputedValues computedValues; + childBox->computeLogicalHeight(childBox->borderAndPaddingLogicalHeight(), 0, computedValues); + childMinPreferredLogicalWidth = childMaxPreferredLogicalWidth = computedValues.m_extent; + } else { + childMinPreferredLogicalWidth = child->minPreferredLogicalWidth(); + childMaxPreferredLogicalWidth = child->maxPreferredLogicalWidth(); + } + childMin += childMinPreferredLogicalWidth.ceilToFloat(); + childMax += childMaxPreferredLogicalWidth.ceilToFloat(); + + bool clearPreviousFloat; + if (child->isFloating()) { + clearPreviousFloat = (prevFloat + && ((prevFloat->style()->floating() == LeftFloat && (childStyle->clear() & CLEFT)) + || (prevFloat->style()->floating() == RightFloat && (childStyle->clear() & CRIGHT)))); + prevFloat = child; + } else { + clearPreviousFloat = false; + } + + bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak; + if ((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) { + updatePreferredWidth(minLogicalWidth, inlineMin); + inlineMin = 0; + } + + // If we're supposed to clear the previous float, then terminate maxwidth as well. + if (clearPreviousFloat) { + updatePreferredWidth(maxLogicalWidth, inlineMax); + inlineMax = 0; + } + + // Add in text-indent. This is added in only once. + if (!addedTextIndent && !child->isFloating()) { + float ceiledTextIndent = textIndent.ceilToFloat(); + childMin += ceiledTextIndent; + childMax += ceiledTextIndent; + + if (childMin < 0) + textIndent = adjustFloatForSubPixelLayout(childMin); + else + addedTextIndent = true; + } + + // Add our width to the max. + inlineMax += max<float>(0, childMax); + + if (!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) { + if (child->isFloating()) + updatePreferredWidth(minLogicalWidth, childMin); + else + inlineMin += childMin; + } else { + // Now check our line. + updatePreferredWidth(minLogicalWidth, childMin); + + // Now start a new line. + inlineMin = 0; + } + + if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) { + updatePreferredWidth(minLogicalWidth, inlineMin); + inlineMin = 0; + } + + // We are no longer stripping whitespace at the start of + // a line. + if (!child->isFloating()) { + stripFrontSpaces = false; + trailingSpaceChild = 0; + } + } else if (child->isText()) { + // Case (3). Text. + RenderText* t = toRenderText(child); + + if (t->isWordBreak()) { + updatePreferredWidth(minLogicalWidth, inlineMin); + inlineMin = 0; + continue; + } + + if (t->style()->hasTextCombine() && t->isCombineText()) + toRenderCombineText(t)->combineText(); + + // Determine if we have a breakable character. Pass in + // whether or not we should ignore any spaces at the front + // of the string. If those are going to be stripped out, + // then they shouldn't be considered in the breakable char + // check. + bool hasBreakableChar, hasBreak; + float firstLineMinWidth, lastLineMinWidth; + bool hasBreakableStart, hasBreakableEnd; + float firstLineMaxWidth, lastLineMaxWidth; + t->trimmedPrefWidths(inlineMax, + firstLineMinWidth, hasBreakableStart, lastLineMinWidth, hasBreakableEnd, + hasBreakableChar, hasBreak, firstLineMaxWidth, lastLineMaxWidth, + childMin, childMax, stripFrontSpaces, styleToUse->direction()); + + // This text object will not be rendered, but it may still provide a breaking opportunity. + if (!hasBreak && !childMax) { + if (autoWrap && (hasBreakableStart || hasBreakableEnd)) { + updatePreferredWidth(minLogicalWidth, inlineMin); + inlineMin = 0; + } + continue; + } + + if (stripFrontSpaces) + trailingSpaceChild = child; + else + trailingSpaceChild = 0; + + // Add in text-indent. This is added in only once. + float ti = 0; + if (!addedTextIndent || hasRemainingNegativeTextIndent) { + ti = textIndent.ceilToFloat(); + childMin += ti; + firstLineMinWidth += ti; + + // It the text indent negative and larger than the child minimum, we re-use the remainder + // in future minimum calculations, but using the negative value again on the maximum + // will lead to under-counting the max pref width. + if (!addedTextIndent) { + childMax += ti; + firstLineMaxWidth += ti; + addedTextIndent = true; + } + + if (childMin < 0) { + textIndent = childMin; + hasRemainingNegativeTextIndent = true; + } + } + + // If we have no breakable characters at all, + // then this is the easy case. We add ourselves to the current + // min and max and continue. + if (!hasBreakableChar) { + inlineMin += childMin; + } else { + if (hasBreakableStart) { + updatePreferredWidth(minLogicalWidth, inlineMin); + } else { + inlineMin += firstLineMinWidth; + updatePreferredWidth(minLogicalWidth, inlineMin); + childMin -= ti; + } + + inlineMin = childMin; + + if (hasBreakableEnd) { + updatePreferredWidth(minLogicalWidth, inlineMin); + inlineMin = 0; + shouldBreakLineAfterText = false; + } else { + updatePreferredWidth(minLogicalWidth, inlineMin); + inlineMin = lastLineMinWidth; + shouldBreakLineAfterText = true; + } + } + + if (hasBreak) { + inlineMax += firstLineMaxWidth; + updatePreferredWidth(maxLogicalWidth, inlineMax); + updatePreferredWidth(maxLogicalWidth, childMax); + inlineMax = lastLineMaxWidth; + addedTextIndent = true; + } else { + inlineMax += max<float>(0, childMax); + } + } + + // Ignore spaces after a list marker. + if (child->isListMarker()) + stripFrontSpaces = true; + } else { + updatePreferredWidth(minLogicalWidth, inlineMin); + updatePreferredWidth(maxLogicalWidth, inlineMax); + inlineMin = inlineMax = 0; + stripFrontSpaces = true; + trailingSpaceChild = 0; + addedTextIndent = true; + } + + if (!child->isText() && child->isRenderInline()) + isPrevChildInlineFlow = true; + else + isPrevChildInlineFlow = false; + + oldAutoWrap = autoWrap; + } + + if (styleToUse->collapseWhiteSpace()) + stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild); + + updatePreferredWidth(minLogicalWidth, inlineMin); + updatePreferredWidth(maxLogicalWidth, inlineMax); +} + +void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom, LayoutUnit afterEdge) +{ RenderFlowThread* flowThread = flowThreadContainingBlock(); bool clearLinesForPagination = firstLineBox() && flowThread && !flowThread->hasRegions(); @@ -1752,25 +1687,17 @@ void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& re // the replaced elements later. In partial layout mode, line boxes are not // deleted and only dirtied. In that case, we can layout the replaced // elements at the same time. - bool hasInlineChild = false; Vector<RenderBox*> replacedChildren; for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) { RenderObject* o = walker.current(); - LayoutRectRecorder recorder(*o, !o->isText()); - - if (!hasInlineChild && o->isInline()) - hasInlineChild = true; + if (!layoutState.hasInlineChild() && o->isInline()) + layoutState.setHasInlineChild(true); if (o->isReplaced() || o->isFloating() || o->isOutOfFlowPositioned()) { RenderBox* box = toRenderBox(o); - if (relayoutChildren || box->hasRelativeDimensions()) - o->setChildNeedsLayout(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(MarkOnlyThis); + updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, box); if (o->isOutOfFlowPositioned()) o->containingBlock()->insertPositionedObject(box); @@ -1796,7 +1723,7 @@ void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& re for (size_t i = 0; i < replacedChildren.size(); i++) replacedChildren[i]->layoutIfNeeded(); - layoutRunsAndFloats(layoutState, hasInlineChild); + layoutRunsAndFloats(layoutState); } // Expand the last line to accommodate Ruby and emphasis marks. @@ -1810,7 +1737,7 @@ void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& re } // Now add in the bottom border/padding. - setLogicalHeight(logicalHeight() + lastLineAnnotationsAdjustment + borderAfter() + paddingAfter() + scrollbarLogicalHeight()); + setLogicalHeight(logicalHeight() + lastLineAnnotationsAdjustment + afterEdge); if (!firstLineBox() && hasLineIfEmpty()) setLogicalHeight(logicalHeight() + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes)); @@ -1865,10 +1792,6 @@ RootInlineBox* RenderBlockFlow::determineStartPosition(LineLayoutState& layoutSt size_t floatIndex = 0; for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox()) { if (paginated) { - if (lineWidthForPaginatedLineChanged(curr, 0, layoutState.flowThread())) { - curr->markDirty(); - break; - } paginationDelta -= curr->paginationStrut(); adjustLinePositionForPagination(curr, paginationDelta, layoutState.flowThread()); if (paginationDelta) { @@ -1879,10 +1802,8 @@ RootInlineBox* RenderBlockFlow::determineStartPosition(LineLayoutState& layoutSt } layoutState.updateRepaintRangeFromBox(curr, paginationDelta); - curr->adjustBlockDirectionPosition(paginationDelta); + curr->adjustBlockDirectionPosition(paginationDelta.toFloat()); } - if (layoutState.flowThread()) - updateRegionForLine(curr); } // If a new float has been inserted before this line or before its last known float, just do a full layout. @@ -1900,6 +1821,13 @@ RootInlineBox* RenderBlockFlow::determineStartPosition(LineLayoutState& layoutSt } if (layoutState.isFullLayout()) { + // If we encountered a new float and have inline children, mark ourself to force us to issue paint invalidations. + if (layoutState.hasInlineChild() && !selfNeedsLayout()) { + setNeedsLayoutAndFullPaintInvalidation(MarkOnlyThis); + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + setShouldDoFullPaintInvalidationAfterLayout(true); + } + // FIXME: This should just call deleteLineBoxTree, but that causes // crashes for fast/repaint tests. curr = firstRootBox(); @@ -2028,8 +1956,6 @@ bool RenderBlockFlow::checkPaginationAndFloatsAtEndLine(LineLayoutState& layoutS adjustLinePositionForPagination(lineBox, lineDelta, layoutState.flowThread()); lineBox->setPaginationStrut(oldPaginationStrut); } - if (lineWidthForPaginatedLineChanged(lineBox, lineDelta, layoutState.flowThread())) - return false; } } @@ -2048,7 +1974,7 @@ bool RenderBlockFlow::checkPaginationAndFloatsAtEndLine(LineLayoutState& layoutS const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); FloatingObjectSetIterator end = floatingObjectSet.end(); for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); if (logicalBottomForFloat(floatingObject) >= logicalTop && logicalBottomForFloat(floatingObject) < logicalBottom) return false; } @@ -2070,7 +1996,7 @@ bool RenderBlockFlow::matchedEndLine(LineLayoutState& layoutState, const InlineB RootInlineBox* originalEndLine = layoutState.endLine(); RootInlineBox* line = originalEndLine; for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) { - if (line->lineBreakObj() == resolver.position().object() && line->lineBreakPos() == resolver.position().m_pos) { + if (line->lineBreakObj() == resolver.position().object() && line->lineBreakPos() == resolver.position().offset()) { // We have a match. if (line->lineBreakBidiStatus() != resolver.status()) return false; // ...but the bidi state doesn't match. @@ -2105,139 +2031,6 @@ bool RenderBlockFlow::generatesLineBoxesForInlineChild(RenderObject* inlineObj) return !it.atEnd(); } -void LineBreaker::skipLeadingWhitespace(InlineBidiResolver& resolver, LineInfo& lineInfo, - FloatingObject* lastFloatFromPreviousLine, LineWidth& width) -{ - while (!resolver.position().atEnd() && !requiresLineBox(resolver.position(), lineInfo, LeadingWhitespace)) { - RenderObject* object = resolver.position().object(); - if (object->isOutOfFlowPositioned()) { - setStaticPositions(m_block, toRenderBox(object)); - if (object->style()->isOriginalDisplayInlineType()) { - resolver.runs().addRun(createRun(0, 1, object, resolver)); - lineInfo.incrementRunsFromLeadingWhitespace(); - } - } else if (object->isFloating()) - m_block->positionNewFloatOnLine(m_block->insertFloatingObject(toRenderBox(object)), lastFloatFromPreviousLine, lineInfo, width); - else if (object->isText() && object->style()->hasTextCombine() && object->isCombineText() && !toRenderCombineText(object)->isCombined()) { - toRenderCombineText(object)->combineText(); - if (toRenderCombineText(object)->isCombined()) - continue; - } - resolver.position().increment(&resolver); - } - resolver.commitExplicitEmbedding(); -} - -void LineBreaker::reset() -{ - m_positionedObjects.clear(); - m_hyphenated = false; - m_clear = CNONE; -} - -InlineIterator LineBreaker::nextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements) -{ - ShapeInsideInfo* shapeInsideInfo = m_block->layoutShapeInsideInfo(); - - if (!shapeInsideInfo || !shapeInsideInfo->lineOverlapsShapeBounds()) - return nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements); - - InlineIterator end = resolver.position(); - InlineIterator oldEnd = end; - - if (!shapeInsideInfo->hasSegments()) { - end = nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements); - resolver.setPositionIgnoringNestedIsolates(oldEnd); - return oldEnd; - } - - const SegmentList& segments = shapeInsideInfo->segments(); - SegmentRangeList& segmentRanges = shapeInsideInfo->segmentRanges(); - - for (unsigned i = 0; i < segments.size() && !end.atEnd(); i++) { - const InlineIterator segmentStart = resolver.position(); - end = nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements); - - ASSERT(segmentRanges.size() == i); - if (resolver.position().atEnd()) { - segmentRanges.append(LineSegmentRange(segmentStart, end)); - break; - } - if (resolver.position() == end) { - // Nothing fit this segment - end = segmentStart; - segmentRanges.append(LineSegmentRange(segmentStart, segmentStart)); - resolver.setPositionIgnoringNestedIsolates(segmentStart); - } else { - // Note that resolver.position is already skipping some of the white space at the beginning of the line, - // so that's why segmentStart might be different than resolver.position(). - LineSegmentRange range(resolver.position(), end); - segmentRanges.append(range); - resolver.setPosition(end, numberOfIsolateAncestors(end)); - - if (lineInfo.previousLineBrokeCleanly()) { - // If we hit a new line break, just stop adding anything to this line. - break; - } - } - } - resolver.setPositionIgnoringNestedIsolates(oldEnd); - return end; -} - -InlineIterator LineBreaker::nextSegmentBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements) -{ - reset(); - - ASSERT(resolver.position().root() == m_block); - - bool appliedStartWidth = resolver.position().m_pos > 0; - - LineWidth width(*m_block, lineInfo.isFirstLine(), requiresIndent(lineInfo.isFirstLine(), lineInfo.previousLineBrokeCleanly(), m_block->style())); - - skipLeadingWhitespace(resolver, lineInfo, lastFloatFromPreviousLine, width); - - if (resolver.position().atEnd()) - return resolver.position(); - - BreakingContext context(resolver, lineInfo, width, renderTextInfo, lastFloatFromPreviousLine, appliedStartWidth, m_block); - - while (context.currentObject()) { - context.initializeForCurrentObject(); - if (context.currentObject()->isBR()) { - context.handleBR(m_clear); - } else if (context.currentObject()->isOutOfFlowPositioned()) { - context.handleOutOfFlowPositioned(m_positionedObjects); - } else if (context.currentObject()->isFloating()) { - context.handleFloat(); - } else if (context.currentObject()->isRenderInline()) { - context.handleEmptyInline(); - } else if (context.currentObject()->isReplaced()) { - context.handleReplaced(); - } else if (context.currentObject()->isText()) { - if (context.handleText(wordMeasurements, m_hyphenated)) { - // We've hit a hard text line break. Our line break iterator is updated, so go ahead and early return. - return context.lineBreak(); - } - } else { - ASSERT_NOT_REACHED(); - } - - if (context.atEnd()) - return context.handleEndOfLine(); - - context.commitAndUpdateLineBreakIfNeeded(); - - if (context.atEnd()) - return context.handleEndOfLine(); - - context.increment(); - } - - context.clearLineBreakIfFitsOnLine(); - - return context.handleEndOfLine(); -} void RenderBlockFlow::addOverflowFromInlineChildren() { @@ -2262,7 +2055,7 @@ void RenderBlockFlow::deleteEllipsisLineBoxes() curr->clearTruncation(); // Shift the line back where it belongs if we cannot accomodate an ellipsis. - float logicalLeft = pixelSnappedLogicalLeftOffsetForLine(curr->lineTop(), firstLine); + float logicalLeft = logicalLeftOffsetForLine(curr->lineTop(), firstLine).toFloat(); float availableLogicalWidth = logicalRightOffsetForLine(curr->lineTop(), false) - logicalLeft; float totalLogicalWidth = curr->logicalWidth(); updateLogicalWidthForAlignment(textAlign, curr, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0); @@ -2283,8 +2076,10 @@ void RenderBlockFlow::checkLinesForTextOverflow() const Font& font = style()->font(); DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1)); const Font& firstLineFont = firstLineStyle()->font(); - int firstLineEllipsisWidth = firstLineFont.width(constructTextRun(this, firstLineFont, &horizontalEllipsis, 1, firstLineStyle())); - int ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(constructTextRun(this, font, &horizontalEllipsis, 1, style())); + // FIXME: We should probably not hard-code the direction here. https://crbug.com/333004 + TextDirection ellipsisDirection = LTR; + float firstLineEllipsisWidth = firstLineFont.width(constructTextRun(this, firstLineFont, &horizontalEllipsis, 1, firstLineStyle(), ellipsisDirection)); + float ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(constructTextRun(this, font, &horizontalEllipsis, 1, style(), ellipsisDirection)); // 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 @@ -2294,12 +2089,10 @@ void RenderBlockFlow::checkLinesForTextOverflow() ETextAlign textAlign = style()->textAlign(); bool firstLine = true; for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { - // FIXME: Use pixelSnappedLogicalRightOffsetForLine instead of snapping it ourselves once the column workaround in said method has been fixed. - // https://bugs.webkit.org/show_bug.cgi?id=105461 float currLogicalLeft = curr->logicalLeft(); - int blockRightEdge = snapSizeToPixel(logicalRightOffsetForLine(curr->lineTop(), firstLine), currLogicalLeft); - int blockLeftEdge = pixelSnappedLogicalLeftOffsetForLine(curr->lineTop(), firstLine); - int lineBoxEdge = ltr ? snapSizeToPixel(currLogicalLeft + curr->logicalWidth(), currLogicalLeft) : snapSizeToPixel(currLogicalLeft, 0); + LayoutUnit blockRightEdge = logicalRightOffsetForLine(curr->lineTop(), firstLine); + LayoutUnit blockLeftEdge = logicalLeftOffsetForLine(curr->lineTop(), firstLine); + LayoutUnit lineBoxEdge = ltr ? currLogicalLeft + curr->logicalWidth() : currLogicalLeft; if ((ltr && lineBoxEdge > blockRightEdge) || (!ltr && lineBoxEdge < blockLeftEdge)) { // This line spills out of our box in the appropriate direction. Now we need to see if the line // can be truncated. In order for truncation to be possible, the line must have sufficient space to @@ -2309,15 +2102,15 @@ void RenderBlockFlow::checkLinesForTextOverflow() LayoutUnit width = firstLine ? firstLineEllipsisWidth : ellipsisWidth; LayoutUnit blockEdge = ltr ? blockRightEdge : blockLeftEdge; if (curr->lineCanAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width)) { - float totalLogicalWidth = curr->placeEllipsis(ellipsisStr, ltr, blockLeftEdge, blockRightEdge, width); + float totalLogicalWidth = curr->placeEllipsis(ellipsisStr, ltr, blockLeftEdge.toFloat(), blockRightEdge.toFloat(), width.toFloat()); float logicalLeft = 0; // We are only intersted in the delta from the base position. - float truncatedWidth = pixelSnappedLogicalRightOffsetForLine(curr->lineTop(), firstLine); - updateLogicalWidthForAlignment(textAlign, curr, 0, logicalLeft, totalLogicalWidth, truncatedWidth, 0); + float availableLogicalWidth = (blockRightEdge - blockLeftEdge).toFloat(); + updateLogicalWidthForAlignment(textAlign, curr, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0); if (ltr) curr->adjustLogicalPosition(logicalLeft, 0); else - curr->adjustLogicalPosition(-(truncatedWidth - (logicalLeft + totalLogicalWidth)), 0); + curr->adjustLogicalPosition(logicalLeft - (availableLogicalWidth - totalLogicalWidth), 0); } } firstLine = false; @@ -2351,7 +2144,7 @@ bool RenderBlockFlow::positionNewFloatOnLine(FloatingObject* newFloat, FloatingO FloatingObjectSetIterator begin = floatingObjectSet.begin(); while (it != begin) { --it; - FloatingObject* floatingObject = *it; + FloatingObject* floatingObject = it->get(); if (floatingObject == lastFloatFromPreviousLine) break; if (logicalTopForFloat(floatingObject) == logicalHeight() + lineInfo.floatPaginationStrut()) { @@ -2386,7 +2179,7 @@ LayoutUnit RenderBlockFlow::startAlignedOffsetForLine(LayoutUnit position, bool // updateLogicalWidthForAlignment() handles the direction of the block so no need to consider it here float totalLogicalWidth = 0; - float logicalLeft = logicalLeftOffsetForLine(logicalHeight(), false); + float logicalLeft = logicalLeftOffsetForLine(logicalHeight(), false).toFloat(); float availableLogicalWidth = logicalRightOffsetForLine(logicalHeight(), false) - logicalLeft; updateLogicalWidthForAlignment(textAlign, 0, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0); @@ -2395,27 +2188,4 @@ LayoutUnit RenderBlockFlow::startAlignedOffsetForLine(LayoutUnit position, bool return logicalLeft; } -void RenderBlockFlow::layoutLineGridBox() -{ - if (style()->lineGrid() == RenderStyle::initialLineGrid()) { - setLineGridBox(0); - return; - } - - setLineGridBox(0); - - RootInlineBox* lineGridBox = new RootInlineBox(this); - lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode. - lineGridBox->setConstructed(); - GlyphOverflowAndFallbackFontsMap textBoxDataMap; - VerticalPositionCache verticalPositionCache; - lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache); - - setLineGridBox(lineGridBox); - - // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying - // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping - // to this grid. -} - } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderBox.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderBox.cpp index 9c960358ed5..93d89283c7b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderBox.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderBox.cpp @@ -26,40 +26,40 @@ #include "config.h" #include "core/rendering/RenderBox.h" -#include <math.h> -#include <algorithm> -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/dom/Document.h" #include "core/editing/htmlediting.h" +#include "core/frame/FrameHost.h" +#include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" +#include "core/frame/PinchViewport.h" +#include "core/frame/Settings.h" #include "core/html/HTMLElement.h" #include "core/html/HTMLFrameElementBase.h" #include "core/html/HTMLFrameOwnerElement.h" -#include "core/html/HTMLHtmlElement.h" -#include "core/html/HTMLTextAreaElement.h" -#include "core/frame/Frame.h" -#include "core/frame/FrameView.h" #include "core/page/AutoscrollController.h" #include "core/page/EventHandler.h" #include "core/page/Page.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/PaintInfo.h" -#include "core/rendering/RenderBoxRegionInfo.h" +#include "core/rendering/RenderDeprecatedFlexibleBox.h" #include "core/rendering/RenderFlexibleBox.h" -#include "core/rendering/RenderFlowThread.h" #include "core/rendering/RenderGeometryMap.h" #include "core/rendering/RenderGrid.h" #include "core/rendering/RenderInline.h" #include "core/rendering/RenderLayer.h" -#include "core/rendering/RenderLayerCompositor.h" +#include "core/rendering/RenderListBox.h" #include "core/rendering/RenderListMarker.h" -#include "core/rendering/RenderRegion.h" #include "core/rendering/RenderTableCell.h" #include "core/rendering/RenderTheme.h" #include "core/rendering/RenderView.h" +#include "core/rendering/compositing/RenderLayerCompositor.h" +#include "platform/LengthFunctions.h" #include "platform/geometry/FloatQuad.h" #include "platform/geometry/TransformState.h" #include "platform/graphics/GraphicsContextStateSaver.h" +#include <algorithm> +#include <math.h> using namespace std; @@ -69,10 +69,9 @@ using namespace HTMLNames; // Used by flexible boxes when flexing this element and by table cells. typedef WTF::HashMap<const RenderBox*, LayoutUnit> OverrideSizeMap; -static OverrideSizeMap* gOverrideHeightMap = 0; -static OverrideSizeMap* gOverrideWidthMap = 0; // Used by grid elements to properly size their grid items. +// FIXME: Move these into RenderBoxRareData. static OverrideSizeMap* gOverrideContainingBlockLogicalHeightMap = 0; static OverrideSizeMap* gOverrideContainingBlockLogicalWidthMap = 0; @@ -95,64 +94,13 @@ static bool skipBodyBackground(const RenderBox* bodyElementRenderer) RenderBox::RenderBox(ContainerNode* node) : RenderBoxModelObject(node) + , m_intrinsicContentLogicalHeight(-1) , m_minPreferredLogicalWidth(-1) , m_maxPreferredLogicalWidth(-1) - , m_intrinsicContentLogicalHeight(-1) - , m_inlineBoxWrapper(0) { setIsBox(); } -RenderBox::~RenderBox() -{ -} - -LayoutRect RenderBox::borderBoxRectInRegion(RenderRegion* region, RenderBoxRegionInfoFlags cacheFlag) const -{ - if (!region) - return borderBoxRect(); - - // Compute the logical width and placement in this region. - RenderBoxRegionInfo* boxInfo = renderBoxRegionInfo(region, cacheFlag); - if (!boxInfo) - return borderBoxRect(); - - // We have cached insets. - LayoutUnit logicalWidth = boxInfo->logicalWidth(); - LayoutUnit logicalLeft = boxInfo->logicalLeft(); - - // Now apply the parent inset since it is cumulative whenever anything in the containing block chain shifts. - // FIXME: Doesn't work right with perpendicular writing modes. - const RenderBlock* currentBox = containingBlock(); - RenderBoxRegionInfo* currentBoxInfo = currentBox->renderBoxRegionInfo(region); - while (currentBoxInfo && currentBoxInfo->isShifted()) { - if (currentBox->style()->direction() == LTR) - logicalLeft += currentBoxInfo->logicalLeft(); - else - logicalLeft -= (currentBox->logicalWidth() - currentBoxInfo->logicalWidth()) - currentBoxInfo->logicalLeft(); - currentBox = currentBox->containingBlock(); - region = currentBox->clampToStartAndEndRegions(region); - currentBoxInfo = currentBox->renderBoxRegionInfo(region); - } - - if (cacheFlag == DoNotCacheRenderBoxRegionInfo) - delete boxInfo; - - if (isHorizontalWritingMode()) - return LayoutRect(logicalLeft, 0, logicalWidth, height()); - return LayoutRect(0, logicalLeft, width(), logicalWidth); -} - -void RenderBox::clearRenderBoxRegionInfo() -{ - if (isRenderFlowThread()) - return; - - RenderFlowThread* flowThread = flowThreadContainingBlock(); - if (flowThread) - flowThread->removeRenderBoxRegionInfo(this); -} - void RenderBox::willBeDestroyed() { clearOverrideSize(); @@ -160,7 +108,7 @@ void RenderBox::willBeDestroyed() RenderBlock::removePercentHeightDescendantIfNeeded(this); - ShapeOutsideInfo::removeInfo(this); + ShapeOutsideInfo::removeInfo(*this); RenderBoxModelObject::willBeDestroyed(); } @@ -192,33 +140,36 @@ void RenderBox::removeFloatingOrPositionedChildFromBlockLists() RenderBlock::removePositionedObject(this); } -void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) +void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle& newStyle) { RenderStyle* oldStyle = style(); if (oldStyle) { // The background of the root element or the body element could propagate up to // the canvas. Just dirty the entire canvas when our style changes substantially. - if (diff >= StyleDifferenceRepaint && node() && - (isHTMLHtmlElement(node()) || node()->hasTagName(bodyTag))) { - view()->repaint(); + if ((diff.needsRepaint() || diff.needsLayout()) && node() + && (isHTMLHtmlElement(*node()) || isHTMLBodyElement(*node()))) { + view()->paintInvalidationForWholeRenderer(); - if (oldStyle->hasEntirelyFixedBackground() != newStyle->hasEntirelyFixedBackground()) - view()->compositor()->rootFixedBackgroundsChanged(); + if (oldStyle->hasEntirelyFixedBackground() != newStyle.hasEntirelyFixedBackground()) + view()->compositor()->setNeedsUpdateFixedBackground(); } // When a layout hint happens and an object's position style changes, we have to do a layout // to dirty the render tree using the old position value now. - if (diff == StyleDifferenceLayout && parent() && oldStyle->position() != newStyle->position()) { + if (diff.needsFullLayout() && parent() && oldStyle->position() != newStyle.position()) { markContainingBlocksForLayout(); if (oldStyle->position() == StaticPosition) - repaint(); - else if (newStyle->hasOutOfFlowPosition()) + paintInvalidationForWholeRenderer(); + else if (newStyle.hasOutOfFlowPosition()) parent()->setChildNeedsLayout(); - if (isFloating() && !isOutOfFlowPositioned() && newStyle->hasOutOfFlowPosition()) + if (isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition()) removeFloatingOrPositionedChildFromBlockLists(); } - } else if (newStyle && isBody()) - view()->repaint(); + // FIXME: This branch runs when !oldStyle, which means that layout was never called + // so what's the point in invalidating the whole view that we never painted? + } else if (isBody()) { + view()->paintInvalidationForWholeRenderer(); + } RenderBoxModelObject::styleWillChange(diff, newStyle); } @@ -244,7 +195,7 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle parent()->setChildNeedsLayout(); } - if (RenderBlock::hasPercentHeightContainerMap() && firstChild() + if (RenderBlock::hasPercentHeightContainerMap() && slowFirstChild() && oldHorizontalWritingMode != isHorizontalWritingMode()) RenderBlock::clearPercentHeightDescendantsFrom(this); @@ -262,7 +213,7 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle } // Our opaqueness might have changed without triggering layout. - if (diff == StyleDifferenceRepaint || diff == StyleDifferenceRepaintIfTextOrColorChange || diff == StyleDifferenceRepaintLayer) { + if (diff.needsRepaint()) { RenderObject* parentToInvalidate = parent(); for (unsigned i = 0; i < backgroundObscurationTestMaxDepth && parentToInvalidate; ++i) { parentToInvalidate->invalidateBackgroundObscurationStatus(); @@ -270,7 +221,7 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle } } - if (isRoot() || isBody()) + if (isDocumentElement() || isBody()) document().view()->recalculateScrollbarOverlayStyle(); updateShapeOutsideInfoAfterStyleChange(*style(), oldStyle); @@ -293,9 +244,9 @@ void RenderBox::updateShapeOutsideInfoAfterStyleChange(const RenderStyle& style, return; if (!shapeOutside) - ShapeOutsideInfo::removeInfo(this); + ShapeOutsideInfo::removeInfo(*this); else - ShapeOutsideInfo::ensureInfo(this)->dirtyShapeSize(); + ShapeOutsideInfo::ensureInfo(*this).markShapeAsDirty(); if (shapeOutside || shapeOutside != oldShapeOutside) markShapeOutsideDependentsForLayout(); @@ -324,7 +275,7 @@ void RenderBox::updateFromStyle() RenderBoxModelObject::updateFromStyle(); RenderStyle* styleToUse = style(); - bool isRootObject = isRoot(); + bool isRootObject = isDocumentElement(); bool isViewObject = isRenderView(); // The root and the RenderView always paint their backgrounds/borders. @@ -334,26 +285,26 @@ void RenderBox::updateFromStyle() setFloating(!isOutOfFlowPositioned() && styleToUse->isFloating()); bool boxHasOverflowClip = false; - // We also handle <body> and <html>, whose overflow applies to the viewport. - // It's sufficient to just check one direction, since it's illegal to have visible on only one overflow value. - if (styleToUse->overflowX() != OVISIBLE && !isRootObject && isRenderBlock()) { - // Overflow on the body can propagate to the viewport under the following conditions. - // (1) The root element is <html>. - // (2) We are the primary <body> (can be checked by looking at document.body). - // (3) The root element has visible overflow. - if (isBody() && isHTMLHtmlElement(document().documentElement()) - && document().body() == node() - && document().documentElement()->renderer()->style()->overflowX() == OVISIBLE) { - boxHasOverflowClip = false; - } else { + if (!styleToUse->isOverflowVisible() && isRenderBlock() && !isViewObject) { + // If overflow has been propagated to the viewport, it has no effect here. + if (node() != document().viewportDefiningElement()) { boxHasOverflowClip = true; if (!hasOverflowClip()) { // If we are getting an overflow clip, preemptively erase any overflowing content. // FIXME: This should probably consult RenderOverflow. - repaint(); + if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + paintInvalidationForWholeRenderer(); } } } + + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && (boxHasOverflowClip != hasOverflowClip())) { + // FIXME: This shouldn't be required if we tracked the visual overflow + // generated by positioned children or self painting layers. crbug.com/345403 + for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling()) + child->setShouldDoFullPaintInvalidationIfSelfPaintingLayer(true); + } + setHasOverflowClip(boxHasOverflowClip); setHasTransform(styleToUse->hasTransformRelatedProperty()); @@ -364,21 +315,18 @@ void RenderBox::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); - - RenderObject* child = firstChild(); + RenderObject* child = slowFirstChild(); if (!child) { clearNeedsLayout(); return; } - LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode()); + LayoutState state(*this, locationOffset()); while (child) { child->layoutIfNeeded(); ASSERT(!child->needsLayout()); child = child->nextSibling(); } - statePusher.pop(); invalidateBackgroundObscurationStatus(); clearNeedsLayout(); } @@ -415,88 +363,65 @@ int RenderBox::pixelSnappedOffsetHeight() const return snapSizeToPixel(offsetHeight(), y() + clientTop()); } -bool RenderBox::canDetermineWidthWithoutLayout() const -{ - // FIXME: This optimization is incorrect as written. - // We need to be able to opt-in to this behavior only when - // it's guarentted correct. - // Until then disabling this optimization to be safe. - return false; - - // FIXME: There are likely many subclasses of RenderBlockFlow which - // cannot determine their layout just from style! - // Perhaps we should create a "PlainRenderBlockFlow" - // and move this optimization there? - if (!isRenderBlockFlow() - // Flexbox items can be expanded beyond their width. - || isFlexItemIncludingDeprecated() - // Table Layout controls cell size and can expand beyond width. - || isTableCell()) - return false; - - RenderStyle* style = this->style(); - return style->width().isFixed() - && style->minWidth().isFixed() - && (style->maxWidth().isUndefined() || style->maxWidth().isFixed()) - && style->paddingLeft().isFixed() - && style->paddingRight().isFixed() - && style->boxSizing() == CONTENT_BOX; -} - -LayoutUnit RenderBox::fixedOffsetWidth() const -{ - ASSERT(canDetermineWidthWithoutLayout()); - - RenderStyle* style = this->style(); - - LayoutUnit width = std::max(LayoutUnit(style->minWidth().value()), LayoutUnit(style->width().value())); - if (style->maxWidth().isFixed()) - width = std::min(LayoutUnit(style->maxWidth().value()), width); - - LayoutUnit borderLeft = style->borderLeft().nonZero() ? style->borderLeft().width() : 0; - LayoutUnit borderRight = style->borderRight().nonZero() ? style->borderRight().width() : 0; - - return width + borderLeft + borderRight + style->paddingLeft().value() + style->paddingRight().value(); -} - -int RenderBox::scrollWidth() const +LayoutUnit RenderBox::scrollWidth() const { if (hasOverflowClip()) return layer()->scrollableArea()->scrollWidth(); // For objects with visible overflow, this matches IE. // FIXME: Need to work right with writing modes. if (style()->isLeftToRightDirection()) - return snapSizeToPixel(max(clientWidth(), layoutOverflowRect().maxX() - borderLeft()), x() + clientLeft()); + return max(clientWidth(), layoutOverflowRect().maxX() - borderLeft()); return clientWidth() - min<LayoutUnit>(0, layoutOverflowRect().x() - borderLeft()); } -int RenderBox::scrollHeight() const +LayoutUnit RenderBox::scrollHeight() const { if (hasOverflowClip()) return layer()->scrollableArea()->scrollHeight(); // For objects with visible overflow, this matches IE. // FIXME: Need to work right with writing modes. - return snapSizeToPixel(max(clientHeight(), layoutOverflowRect().maxY() - borderTop()), y() + clientTop()); + return max(clientHeight(), layoutOverflowRect().maxY() - borderTop()); } -int RenderBox::scrollLeft() const +LayoutUnit RenderBox::scrollLeft() const { return hasOverflowClip() ? layer()->scrollableArea()->scrollXOffset() : 0; } -int RenderBox::scrollTop() const +LayoutUnit RenderBox::scrollTop() const { return hasOverflowClip() ? layer()->scrollableArea()->scrollYOffset() : 0; } -void RenderBox::setScrollLeft(int newLeft) +int RenderBox::pixelSnappedScrollWidth() const +{ + return snapSizeToPixel(scrollWidth(), x() + clientLeft()); +} + +int RenderBox::pixelSnappedScrollHeight() const +{ + if (hasOverflowClip()) + return layer()->scrollableArea()->scrollHeight(); + // For objects with visible overflow, this matches IE. + // FIXME: Need to work right with writing modes. + return snapSizeToPixel(scrollHeight(), y() + clientTop()); +} + +void RenderBox::setScrollLeft(LayoutUnit newLeft) { + // This doesn't hit in any tests, but since the equivalent code in setScrollTop + // does, presumably this code does as well. + DisableCompositingQueryAsserts disabler; + if (hasOverflowClip()) layer()->scrollableArea()->scrollToXOffset(newLeft, ScrollOffsetClamped); } -void RenderBox::setScrollTop(int newTop) +void RenderBox::setScrollTop(LayoutUnit newTop) { + // Hits in compositing/overflow/do-not-assert-on-invisible-composited-layers.html + DisableCompositingQueryAsserts disabler; + if (hasOverflowClip()) layer()->scrollableArea()->scrollToYOffset(newTop, ScrollOffsetClamped); } @@ -504,6 +429,10 @@ void RenderBox::setScrollTop(int newTop) void RenderBox::scrollToOffset(const IntSize& offset) { ASSERT(hasOverflowClip()); + + // This doesn't hit in any tests, but since the equivalent code in setScrollTop + // does, presumably this code does as well. + DisableCompositingQueryAsserts disabler; layer()->scrollableArea()->scrollToOffset(offset, ScrollOffsetClamped); } @@ -527,6 +456,9 @@ static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameEl void RenderBox::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY) { + // Presumably the same issue as in setScrollTop. See crbug.com/343132. + DisableCompositingQueryAsserts disabler; + RenderBox* parentBox = 0; LayoutRect newRect = rect; @@ -547,7 +479,7 @@ void RenderBox::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignmen if (ownerElement && ownerElement->renderer()) { HTMLFrameElementBase* frameElementBase = 0; - if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) + if (isHTMLFrameElement(*ownerElement) || isHTMLIFrameElement(*ownerElement)) frameElementBase = toHTMLFrameElementBase(ownerElement); if (frameElementAndViewPermitScroll(frameElementBase, frameView)) { @@ -572,9 +504,15 @@ void RenderBox::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignmen } } } else { - LayoutRect viewRect = frameView->visibleContentRect(); - LayoutRect r = ScrollAlignment::getRectToExpose(viewRect, rect, alignX, alignY); - frameView->setScrollPosition(roundedIntPoint(r.location())); + if (frame()->settings()->pinchVirtualViewportEnabled()) { + PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport(); + LayoutRect r = ScrollAlignment::getRectToExpose(LayoutRect(pinchViewport.visibleRectInDocument()), rect, alignX, alignY); + pinchViewport.scrollIntoView(r); + } else { + LayoutRect viewRect = frameView->visibleContentRect(); + LayoutRect r = ScrollAlignment::getRectToExpose(viewRect, rect, alignX, alignY); + frameView->setScrollPosition(roundedIntPoint(r.location())); + } } } } @@ -593,22 +531,22 @@ void RenderBox::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumul void RenderBox::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const { - quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height()), 0 /* mode */, wasFixed)); + quads.append(localToAbsoluteQuad(FloatRect(0, 0, width().toFloat(), height().toFloat()), 0 /* mode */, wasFixed)); } -void RenderBox::updateLayerTransform() +void RenderBox::updateLayerTransformAfterLayout() { // Transform-origin depends on box size, so we need to update the layer transform after layout. if (hasLayer()) - layer()->updateTransform(); + layer()->updateTransformationMatrix(); } -LayoutUnit RenderBox::constrainLogicalWidthInRegionByMinMax(LayoutUnit logicalWidth, LayoutUnit availableWidth, RenderBlock* cb, RenderRegion* region) const +LayoutUnit RenderBox::constrainLogicalWidthByMinMax(LayoutUnit logicalWidth, LayoutUnit availableWidth, RenderBlock* cb) const { RenderStyle* styleToUse = style(); if (!styleToUse->logicalMaxWidth().isUndefined()) - logicalWidth = min(logicalWidth, computeLogicalWidthInRegionUsing(MaxSize, styleToUse->logicalMaxWidth(), availableWidth, cb, region)); - return max(logicalWidth, computeLogicalWidthInRegionUsing(MinSize, styleToUse->logicalMinWidth(), availableWidth, cb, region)); + logicalWidth = min(logicalWidth, computeLogicalWidthUsing(MaxSize, styleToUse->logicalMaxWidth(), availableWidth, cb)); + return max(logicalWidth, computeLogicalWidthUsing(MinSize, styleToUse->logicalMinWidth(), availableWidth, cb)); } LayoutUnit RenderBox::constrainLogicalHeightByMinMax(LayoutUnit logicalHeight, LayoutUnit intrinsicContentHeight) const @@ -648,28 +586,6 @@ FloatQuad RenderBox::absoluteContentQuad() const return localToAbsoluteQuad(FloatRect(rect)); } -LayoutRect RenderBox::outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap) const -{ - LayoutRect box = borderBoundingBox(); - adjustRectForOutlineAndShadow(box); - - if (repaintContainer != this) { - FloatQuad containerRelativeQuad; - if (geometryMap) - containerRelativeQuad = geometryMap->mapToContainer(box, repaintContainer); - else - containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer); - - box = containerRelativeQuad.enclosingBoundingBox(); - } - - // FIXME: layoutDelta needs to be applied in parts before/after transforms and - // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 - box.move(view()->layoutDelta()); - - return box; -} - void RenderBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*) { if (!size().isEmpty()) @@ -696,38 +612,13 @@ void RenderBox::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutP rects.append(LayoutRect(layerOffset, size())); } -LayoutRect RenderBox::reflectionBox() const -{ - LayoutRect result; - if (!style()->boxReflect()) - return result; - LayoutRect box = borderBoxRect(); - result = box; - switch (style()->boxReflect()->direction()) { - case ReflectionBelow: - result.move(0, box.height() + reflectionOffset()); - break; - case ReflectionAbove: - result.move(0, -box.height() - reflectionOffset()); - break; - case ReflectionLeft: - result.move(-box.width() - reflectionOffset(), 0); - break; - case ReflectionRight: - result.move(box.width() + reflectionOffset(), 0); - break; - } - return result; -} - int RenderBox::reflectionOffset() const { if (!style()->boxReflect()) return 0; - RenderView* renderView = view(); if (style()->boxReflect()->direction() == ReflectionLeft || style()->boxReflect()->direction() == ReflectionRight) - return valueForLength(style()->boxReflect()->offset(), borderBoxRect().width(), renderView); - return valueForLength(style()->boxReflect()->offset(), borderBoxRect().height(), renderView); + return valueForLength(style()->boxReflect()->offset(), borderBoxRect().width()); + return valueForLength(style()->boxReflect()->offset(), borderBoxRect().height()); } LayoutRect RenderBox::reflectedRect(const LayoutRect& r) const @@ -788,20 +679,23 @@ int RenderBox::instrinsicScrollbarLogicalWidth() const return 0; } -bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier) +bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float delta) { + // Presumably the same issue as in setScrollTop. See crbug.com/343132. + DisableCompositingQueryAsserts disabler; + // Logical scroll is a higher level concept, all directions by here must be physical ASSERT(!isLogical(direction)); if (!layer() || !layer()->scrollableArea()) return false; - return layer()->scrollableArea()->scroll(direction, granularity, multiplier); + return layer()->scrollableArea()->scroll(direction, granularity, delta); } bool RenderBox::canBeScrolledAndHasScrollableArea() const { - return canBeProgramaticallyScrolled() && (scrollHeight() != clientHeight() || scrollWidth() != clientWidth()); + return canBeProgramaticallyScrolled() && (pixelSnappedScrollHeight() != pixelSnappedClientHeight() || pixelSnappedScrollWidth() != pixelSnappedClientWidth()); } bool RenderBox::canBeProgramaticallyScrolled() const @@ -827,7 +721,7 @@ bool RenderBox::usesCompositedScrolling() const void RenderBox::autoscroll(const IntPoint& position) { - Frame* frame = this->frame(); + LocalFrame* frame = this->frame(); if (!frame) return; @@ -918,7 +812,7 @@ static inline IntSize adjustedScrollDelta(const IntSize& delta) void RenderBox::panScroll(const IntPoint& sourcePoint) { - Frame* frame = this->frame(); + LocalFrame* frame = this->frame(); if (!frame) return; @@ -960,7 +854,7 @@ void RenderBox::scrollByRecursively(const IntSize& delta, ScrollOffsetClamping c if (RenderBox* scrollableBox = enclosingScrollableBox()) scrollableBox->scrollByRecursively(remainingScrollOffset, clamp); - Frame* frame = this->frame(); + LocalFrame* frame = this->frame(); if (frame && frame->page()) frame->page()->autoscrollController().updateAutoscrollRenderer(); } @@ -995,17 +889,21 @@ LayoutSize RenderBox::cachedSizeForOverflowClip() const void RenderBox::applyCachedClipAndScrollOffsetForRepaint(LayoutRect& paintRect) const { + flipForWritingMode(paintRect); paintRect.move(-scrolledContentOffset()); // For overflow:auto/scroll/hidden. // Do not clip scroll layer contents to reduce the number of repaints while scrolling. - if (usesCompositedScrolling()) + if (usesCompositedScrolling()) { + flipForWritingMode(paintRect); return; + } // height() is inaccurate if we're in the middle of a layout of this RenderBox, so use the // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint // anyway if its size does change. LayoutRect clipRect(LayoutPoint(), cachedSizeForOverflowClip()); paintRect = intersection(paintRect, clipRect); + flipForWritingMode(paintRect); } void RenderBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const @@ -1018,7 +916,7 @@ LayoutUnit RenderBox::minPreferredLogicalWidth() const { if (preferredLogicalWidthsDirty()) { #ifndef NDEBUG - SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox*>(this)); + SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox&>(*this)); #endif const_cast<RenderBox*>(this)->computePreferredLogicalWidths(); } @@ -1030,7 +928,7 @@ LayoutUnit RenderBox::maxPreferredLogicalWidth() const { if (preferredLogicalWidthsDirty()) { #ifndef NDEBUG - SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox*>(this)); + SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox&>(*this)); #endif const_cast<RenderBox*>(this)->computePreferredLogicalWidths(); } @@ -1040,38 +938,36 @@ LayoutUnit RenderBox::maxPreferredLogicalWidth() const bool RenderBox::hasOverrideHeight() const { - return gOverrideHeightMap && gOverrideHeightMap->contains(this); + return m_rareData && m_rareData->m_overrideLogicalContentHeight != -1; } bool RenderBox::hasOverrideWidth() const { - return gOverrideWidthMap && gOverrideWidthMap->contains(this); + return m_rareData && m_rareData->m_overrideLogicalContentWidth != -1; } void RenderBox::setOverrideLogicalContentHeight(LayoutUnit height) { - if (!gOverrideHeightMap) - gOverrideHeightMap = new OverrideSizeMap(); - gOverrideHeightMap->set(this, height); + ASSERT(height >= 0); + ensureRareData().m_overrideLogicalContentHeight = height; } void RenderBox::setOverrideLogicalContentWidth(LayoutUnit width) { - if (!gOverrideWidthMap) - gOverrideWidthMap = new OverrideSizeMap(); - gOverrideWidthMap->set(this, width); + ASSERT(width >= 0); + ensureRareData().m_overrideLogicalContentWidth = width; } void RenderBox::clearOverrideLogicalContentHeight() { - if (gOverrideHeightMap) - gOverrideHeightMap->remove(this); + if (m_rareData) + m_rareData->m_overrideLogicalContentHeight = -1; } void RenderBox::clearOverrideLogicalContentWidth() { - if (gOverrideWidthMap) - gOverrideWidthMap->remove(this); + if (m_rareData) + m_rareData->m_overrideLogicalContentWidth = -1; } void RenderBox::clearOverrideSize() @@ -1083,13 +979,13 @@ void RenderBox::clearOverrideSize() LayoutUnit RenderBox::overrideLogicalContentWidth() const { ASSERT(hasOverrideWidth()); - return gOverrideWidthMap->get(this); + return m_rareData->m_overrideLogicalContentWidth; } LayoutUnit RenderBox::overrideLogicalContentHeight() const { ASSERT(hasOverrideHeight()); - return gOverrideHeightMap->get(this); + return m_rareData->m_overrideLogicalContentHeight; } LayoutUnit RenderBox::overrideContainingBlockContentLogicalWidth() const @@ -1177,8 +1073,8 @@ bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result LayoutPoint adjustedLocation = accumulatedOffset + location(); // Check kids first. - for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { - if (!child->hasLayer() && child->nodeAtPoint(request, result, locationInContainer, adjustedLocation, action)) { + for (RenderObject* child = slowLastChild(); child; child = child->previousSibling()) { + if ((!child->hasLayer() || !toRenderLayerModelObject(child)->layer()->isSelfPaintingLayer()) && child->nodeAtPoint(request, result, locationInContainer, adjustedLocation, action)) { updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation)); return true; } @@ -1186,7 +1082,7 @@ bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result // Check our bounds next. For this purpose always assume that we can only be hit in the // foreground phase (which is true for replaced elements like images). - LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region()); + LayoutRect boundsRect = borderBoxRect(); boundsRect.moveBy(adjustedLocation); if (visibleToHitTestRequest(request) && action == HitTestForeground && locationInContainer.intersects(boundsRect)) { updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation)); @@ -1205,7 +1101,7 @@ void RenderBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) // default implementation. Just pass paint through to the children PaintInfo childInfo(paintInfo); childInfo.updatePaintingRootForChildren(this); - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) + for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling()) child->paint(childInfo, adjustedPaintOffset); } @@ -1229,9 +1125,11 @@ BackgroundBleedAvoidance RenderBox::determineBackgroundBleedAvoidance(GraphicsCo const RenderStyle* style = this->style(); - if (!style->hasBackground() || !style->hasBorder() || !style->hasBorderRadius() || borderImageIsLoadedAndCanBeRendered()) + if (!style->hasBackground() || !style->hasBorder() || !style->hasBorderRadius() || canRenderBorderImage()) return BackgroundBleedNone; + // FIXME: See crbug.com/382491. getCTM does not accurately reflect the scale at the time content is + // rasterized, and should not be relied on to make decisions about bleeding. AffineTransform ctm = context->getCTM(); FloatSize contextScaling(static_cast<float>(ctm.xScale()), static_cast<float>(ctm.yScale())); @@ -1254,7 +1152,7 @@ BackgroundBleedAvoidance RenderBox::determineBackgroundBleedAvoidance(GraphicsCo if (!style->hasAppearance() && borderObscuresBackground() && backgroundHasOpaqueTopLayer()) return BackgroundBleedBackgroundOverBorder; - return BackgroundBleedUseTransparencyLayer; + return BackgroundBleedClipBackground; } void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset) @@ -1262,7 +1160,7 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& pai if (!paintInfo.shouldPaintWithinRoot(this)) return; - LayoutRect paintRect = borderBoxRectInRegion(paintInfo.renderRegion); + LayoutRect paintRect = borderBoxRect(); paintRect.moveBy(paintOffset); paintBoxDecorationsWithRect(paintInfo, paintOffset, paintRect); } @@ -1277,20 +1175,13 @@ void RenderBox::paintBoxDecorationsWithRect(PaintInfo& paintInfo, const LayoutPo paintBoxShadow(paintInfo, paintRect, style(), Normal); GraphicsContextStateSaver stateSaver(*paintInfo.context, false); - if (bleedAvoidance == BackgroundBleedUseTransparencyLayer) { - // 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, view()); + if (bleedAvoidance == BackgroundBleedClipBackground) { stateSaver.save(); + RoundedRect border = style()->getRoundedBorderFor(paintRect); paintInfo.context->clipRoundedRect(border); - paintInfo.context->beginTransparencyLayer(1); } paintBackgroundWithBorderAndBoxShadow(paintInfo, paintRect, bleedAvoidance); - - if (bleedAvoidance == BackgroundBleedUseTransparencyLayer) - paintInfo.context->endLayer(); } void RenderBox::paintBackgroundWithBorderAndBoxShadow(PaintInfo& paintInfo, const LayoutRect& paintRect, BackgroundBleedAvoidance bleedAvoidance) @@ -1317,7 +1208,7 @@ void RenderBox::paintBackgroundWithBorderAndBoxShadow(PaintInfo& paintInfo, cons void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& paintRect, BackgroundBleedAvoidance bleedAvoidance) { - if (isRoot()) { + if (isDocumentElement()) { paintRootBoxFillLayers(paintInfo); return; } @@ -1328,19 +1219,28 @@ void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& pa paintFillLayers(paintInfo, resolveColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect, bleedAvoidance); } -LayoutRect RenderBox::backgroundPaintedExtent() const +bool RenderBox::getBackgroundPaintedExtent(LayoutRect& paintedExtent) const { ASSERT(hasBackground()); LayoutRect backgroundRect = pixelSnappedIntRect(borderBoxRect()); Color backgroundColor = resolveColor(CSSPropertyBackgroundColor); - if (backgroundColor.isValid() && backgroundColor.alpha()) - return backgroundRect; - if (!style()->backgroundLayers()->image() || style()->backgroundLayers()->next()) - return backgroundRect; + if (backgroundColor.alpha()) { + paintedExtent = backgroundRect; + return true; + } + + if (!style()->backgroundLayers()->image() || style()->backgroundLayers()->next()) { + paintedExtent = backgroundRect; + return true; + } + BackgroundImageGeometry geometry; - const_cast<RenderBox*>(this)->calculateBackgroundImageGeometry(style()->backgroundLayers(), backgroundRect, geometry); - return geometry.destRect(); + calculateBackgroundImageGeometry(0, style()->backgroundLayers(), backgroundRect, geometry); + if (geometry.hasNonLocalGeometry()) + return false; + paintedExtent = geometry.destRect(); + return true; } bool RenderBox::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const @@ -1349,7 +1249,7 @@ bool RenderBox::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) c return false; Color backgroundColor = resolveColor(CSSPropertyBackgroundColor); - if (!backgroundColor.isValid() || backgroundColor.hasAlpha()) + if (backgroundColor.hasAlpha()) return false; // If the element has appearance, it might be painted by theme. @@ -1411,7 +1311,7 @@ bool RenderBox::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, u { if (!maxDepthToTest) return false; - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { + for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling()) { if (!child->isBox()) continue; RenderBox* childBox = toRenderBox(child); @@ -1445,12 +1345,14 @@ bool RenderBox::computeBackgroundIsKnownToBeObscured() if (!hasBackground()) return false; // Table and root background painting is special. - if (isTable() || isRoot()) + if (isTable() || isDocumentElement()) return false; // FIXME: box-shadow is painted while background painting. if (style()->boxShadow()) return false; - LayoutRect backgroundRect = backgroundPaintedExtent(); + LayoutRect backgroundRect; + if (!getBackgroundPaintedExtent(backgroundRect)) + return false; return foregroundIsKnownToBeOpaqueInRect(backgroundRect, backgroundObscurationTestMaxDepth); } @@ -1464,13 +1366,13 @@ bool RenderBox::backgroundHasOpaqueTopLayer() const if (hasOverflowClip() && fillLayer->attachment() == LocalBackgroundAttachment) return false; - if (fillLayer->hasOpaqueImage(this) && fillLayer->hasRepeatXY() && fillLayer->image()->canRender(this, style()->effectiveZoom())) + if (fillLayer->hasOpaqueImage(this) && fillLayer->hasRepeatXY() && fillLayer->image()->canRender(*this, style()->effectiveZoom())) return true; // If there is only one layer and no image, check whether the background color is opaque if (!fillLayer->next() && !fillLayer->hasImage()) { Color bgColor = resolveColor(CSSPropertyBackgroundColor); - if (bgColor.isValid() && bgColor.alpha() == 255) + if (bgColor.alpha() == 255) return true; } @@ -1530,7 +1432,7 @@ void RenderBox::paintMaskImages(const PaintInfo& paintInfo, const LayoutRect& pa } if (allMaskImagesLoaded) { - paintFillLayers(paintInfo, Color(), style()->maskLayers(), paintRect, BackgroundBleedNone, compositeOp); + paintFillLayers(paintInfo, Color::transparent, style()->maskLayers(), paintRect, BackgroundBleedNone, compositeOp); paintNinePieceImage(paintInfo.context, paintRect, style(), style()->maskBoxImage(), compositeOp); } @@ -1538,29 +1440,6 @@ void RenderBox::paintMaskImages(const PaintInfo& paintInfo, const LayoutRect& pa paintInfo.context->endLayer(); } -LayoutRect RenderBox::maskClipRect() -{ - const NinePieceImage& maskBoxImage = style()->maskBoxImage(); - if (maskBoxImage.image()) { - LayoutRect borderImageRect = borderBoxRect(); - - // Apply outsets to the border box. - borderImageRect.expand(style()->maskBoxImageOutsets()); - return borderImageRect; - } - - LayoutRect result; - LayoutRect borderBox = borderBoxRect(); - for (const FillLayer* maskLayer = style()->maskLayers(); maskLayer; maskLayer = maskLayer->next()) { - if (maskLayer->image()) { - BackgroundImageGeometry geometry; - calculateBackgroundImageGeometry(maskLayer, borderBox, geometry); - result.unite(geometry.destRect()); - } - } - return result; -} - void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect, BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject) { @@ -1581,7 +1460,7 @@ void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, cons shouldDrawBackgroundInSeparateBuffer = true; // The clipOccludesNextLayers condition must be evaluated first to avoid short-circuiting. - if (curLayer->clipOccludesNextLayers(curLayer == fillLayer) && curLayer->hasOpaqueImage(this) && curLayer->image()->canRender(this, style()->effectiveZoom()) && curLayer->hasRepeatXY() && curLayer->blendMode() == blink::WebBlendModeNormal && !boxShadowShouldBeAppliedToBackground(bleedAvoidance)) + if (curLayer->clipOccludesNextLayers(curLayer == fillLayer) && curLayer->hasOpaqueImage(this) && curLayer->image()->canRender(*this, style()->effectiveZoom()) && curLayer->hasRepeatXY() && curLayer->blendMode() == blink::WebBlendModeNormal && !boxShadowShouldBeAppliedToBackground(bleedAvoidance)) break; curLayer = curLayer->next(); } @@ -1606,34 +1485,28 @@ void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const paintFillLayerExtended(paintInfo, c, fillLayer, rect, bleedAvoidance, 0, LayoutSize(), op, backgroundObject); } -static bool layersUseImage(WrappedImagePtr image, const FillLayer* layers) -{ - for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) { - if (curLayer->image() && image == curLayer->image()->data()) - return true; - } - - return false; -} - void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*) { if (!parent()) return; + AllowPaintInvalidationScope scoper(frameView()); + if ((style()->borderImage().image() && style()->borderImage().image()->data() == image) || (style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image)) { - repaint(); + paintInvalidationForWholeRenderer(); return; } + ShapeValue* shapeOutsideValue = style()->shapeOutside(); + if (!frameView()->isInPerformLayout() && isFloating() && shapeOutsideValue && shapeOutsideValue->image() && shapeOutsideValue->image()->data() == image) { + ShapeOutsideInfo::ensureInfo(*this).markShapeAsDirty(); + markShapeOutsideDependentsForLayout(); + } + bool didFullRepaint = repaintLayerRectsForImage(image, style()->backgroundLayers(), true); if (!didFullRepaint) repaintLayerRectsForImage(image, style()->maskLayers(), false); - - - if (hasLayer() && layer()->hasCompositedMask() && layersUseImage(image, style()->maskLayers())) - layer()->contentChanged(MaskImageChanged); } bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground) @@ -1642,11 +1515,10 @@ bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer RenderBox* layerRenderer = 0; for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) { - if (curLayer->image() && image == curLayer->image()->data() && curLayer->image()->canRender(this, style()->effectiveZoom())) { - // Now that we know this image is being used, compute the renderer and the rect - // if we haven't already + if (curLayer->image() && image == curLayer->image()->data() && curLayer->image()->canRender(*this, style()->effectiveZoom())) { + // Now that we know this image is being used, compute the renderer and the rect if we haven't already. if (!layerRenderer) { - bool drawingRootBackground = drawingBackground && (isRoot() || (isBody() && !document().documentElement()->renderer()->hasBackground())); + bool drawingRootBackground = drawingBackground && (isDocumentElement() || (isBody() && !document().documentElement()->renderer()->hasBackground())); if (drawingRootBackground) { layerRenderer = view(); @@ -1671,8 +1543,15 @@ bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer } BackgroundImageGeometry geometry; - layerRenderer->calculateBackgroundImageGeometry(curLayer, rendererRect, geometry); - layerRenderer->repaintRectangle(geometry.destRect()); + layerRenderer->calculateBackgroundImageGeometry(0, curLayer, rendererRect, geometry); + if (geometry.hasNonLocalGeometry()) { + // Rather than incur the costs of computing the paintContainer for renderers with fixed backgrounds + // in order to get the right destRect, just repaint the entire renderer. + layerRenderer->paintInvalidationForWholeRenderer(); + return true; + } + + layerRenderer->invalidatePaintRectangle(geometry.destRect()); if (geometry.destRect() == rendererRect) return true; } @@ -1680,6 +1559,80 @@ bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer return false; } +void RenderBox::invalidateTreeAfterLayout(const RenderLayerModelObject& paintInvalidationContainer) +{ + // FIXME: Currently only using this logic for RenderBox and its ilk. Ideally, RenderBlockFlows with + // inline children should track a dirty rect in local coordinates for dirty lines instead of invalidating + // the world. + // FIXME: We should still be recursing through inline's children, as they can have boxes, but we don't + // appear to have tests for this? + // FIXME: SVG should probably also go through this unified paint invalidation system. + + ASSERT(RuntimeEnabledFeatures::repaintAfterLayoutEnabled()); + ASSERT(!needsLayout()); + + if (!shouldCheckForPaintInvalidationAfterLayout()) + return; + + bool establishesNewPaintInvalidationContainer = isPaintInvalidationContainer(); + const RenderLayerModelObject& newPaintInvalidationContainer = *adjustCompositedContainerForSpecialAncestors(establishesNewPaintInvalidationContainer ? this : &paintInvalidationContainer); + // FIXME: This assert should be re-enabled when we move paint invalidation to after compositing update. crbug.com/360286 + // ASSERT(&newPaintInvalidationContainer == containerForPaintInvalidation()); + + const LayoutRect oldPaintInvalidationRect = previousPaintInvalidationRect(); + const LayoutPoint oldPositionFromPaintInvalidationContainer = previousPositionFromPaintInvalidationContainer(); + setPreviousPaintInvalidationRect(boundsRectForPaintInvalidation(&newPaintInvalidationContainer)); + setPreviousPositionFromPaintInvalidationContainer(RenderLayer::positionFromPaintInvalidationContainer(this, &newPaintInvalidationContainer)); + + // If we are set to do a full paint invalidation that means the RenderView will be + // issue paint invalidations. We can then skip issuing of paint invalidations for the child + // renderers as they'll be covered by the RenderView. + if (view()->doingFullRepaint()) { + LayoutState state(*this, isTableRow() ? LayoutSize() : locationOffset()); + RenderObject::invalidateTreeAfterLayout(newPaintInvalidationContainer); + return; + } + + if ((onlyNeededPositionedMovementLayout() && compositingState() != PaintsIntoOwnBacking) + || (shouldDoFullPaintInvalidationIfSelfPaintingLayer() + && hasLayer() + && layer()->isSelfPaintingLayer())) { + setShouldDoFullPaintInvalidationAfterLayout(true); + } + + const LayoutRect& newPaintInvalidationRect = previousPaintInvalidationRect(); + const LayoutPoint& newPositionFromPaintInvalidationContainer = previousPositionFromPaintInvalidationContainer(); + bool didFullPaintInvalidation = invalidatePaintAfterLayoutIfNeeded(&newPaintInvalidationContainer, + shouldDoFullPaintInvalidationAfterLayout(), oldPaintInvalidationRect, oldPositionFromPaintInvalidationContainer, + &newPaintInvalidationRect, &newPositionFromPaintInvalidationContainer); + + if (!didFullPaintInvalidation) + invalidatePaintForOverflowIfNeeded(); + + // Issue paint invalidations for any scrollbars if there is a scrollable area for this renderer. + if (enclosingLayer()) { + if (RenderLayerScrollableArea* area = enclosingLayer()->scrollableArea()) { + if (area->hasVerticalBarDamage()) + invalidatePaintRectangle(area->verticalBarDamage()); + if (area->hasHorizontalBarDamage()) + invalidatePaintRectangle(area->horizontalBarDamage()); + area->resetScrollbarDamage(); + } + } + + // FIXME: LayoutState should be enabled for other paint invalidation containers than the RenderView. crbug.com/363834 + if (establishesNewPaintInvalidationContainer && !isRenderView()) { + ForceHorriblySlowRectMapping slowRectMapping(*this); + RenderObject::invalidateTreeAfterLayout(newPaintInvalidationContainer); + } else { + // FIXME: This concept of a tree walking state for fast lookups should be generalized away from + // just layout. + // FIXME: Table rows shouldn't be special-cased. + LayoutState state(*this, isTableRow() ? LayoutSize() : locationOffset()); + RenderObject::invalidateTreeAfterLayout(newPaintInvalidationContainer); + } +} + bool RenderBox::pushContentsClip(PaintInfo& paintInfo, const LayoutPoint& accumulatedOffset, ContentsClipBehavior contentsClipBehavior) { if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseSelfOutline || paintInfo.phase == PaintPhaseMask) @@ -1691,7 +1644,7 @@ bool RenderBox::pushContentsClip(PaintInfo& paintInfo, const LayoutPoint& accumu if (!isControlClip && !isOverflowClip) return false; - LayoutRect clipRect = isControlClip ? controlClipRect(accumulatedOffset) : overflowClipRect(accumulatedOffset, paintInfo.renderRegion); + LayoutRect clipRect = isControlClip ? controlClipRect(accumulatedOffset) : overflowClipRect(accumulatedOffset); RoundedRect clipRoundedRect(0, 0, 0, 0); bool hasBorderRadius = style()->hasBorderRadius(); if (hasBorderRadius) @@ -1702,11 +1655,6 @@ bool RenderBox::pushContentsClip(PaintInfo& paintInfo, const LayoutPoint& accumu if (contentsVisualOverflow.isEmpty()) return false; - // FIXME: Get rid of this slop from here and elsewhere. - // Instead, properly include the outline in visual overflow. - if (RenderView* view = this->view()) - contentsVisualOverflow.inflate(view->maximalOutlineSize()); - LayoutRect conservativeClipRect = clipRect; if (hasBorderRadius) conservativeClipRect.intersect(clipRoundedRect.radiusCenterRect()); @@ -1744,11 +1692,11 @@ void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase, paintInfo.phase = originalPhase; } -LayoutRect RenderBox::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy) +LayoutRect RenderBox::overflowClipRect(const LayoutPoint& location, OverlayScrollbarSizeRelevancy relevancy) { // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property // here. - LayoutRect clipRect = borderBoxRectInRegion(region); + LayoutRect clipRect = borderBoxRect(); clipRect.setLocation(location + clipRect.location() + LayoutSize(borderLeft(), borderTop())); clipRect.setSize(clipRect.size() - LayoutSize(borderLeft() + borderRight(), borderTop() + borderBottom())); @@ -1763,74 +1711,55 @@ LayoutRect RenderBox::overflowClipRect(const LayoutPoint& location, RenderRegion return clipRect; } -LayoutRect RenderBox::clipRect(const LayoutPoint& location, RenderRegion* region) +LayoutRect RenderBox::clipRect(const LayoutPoint& location) { - LayoutRect borderBoxRect = borderBoxRectInRegion(region); + LayoutRect borderBoxRect = this->borderBoxRect(); LayoutRect clipRect = LayoutRect(borderBoxRect.location() + location, borderBoxRect.size()); - RenderView* renderView = view(); if (!style()->clipLeft().isAuto()) { - LayoutUnit c = valueForLength(style()->clipLeft(), borderBoxRect.width(), renderView); + LayoutUnit c = valueForLength(style()->clipLeft(), borderBoxRect.width()); clipRect.move(c, 0); clipRect.contract(c, 0); } - // We don't use the region-specific border box's width and height since clip offsets are (stupidly) specified - // 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() - valueForLength(style()->clipRight(), width(), renderView), 0); + clipRect.contract(width() - valueForLength(style()->clipRight(), width()), 0); if (!style()->clipTop().isAuto()) { - LayoutUnit c = valueForLength(style()->clipTop(), borderBoxRect.height(), renderView); + LayoutUnit c = valueForLength(style()->clipTop(), borderBoxRect.height()); clipRect.move(0, c); clipRect.contract(0, c); } if (!style()->clipBottom().isAuto()) - clipRect.contract(0, height() - valueForLength(style()->clipBottom(), height(), renderView)); + clipRect.contract(0, height() - valueForLength(style()->clipBottom(), height())); return clipRect; } -LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlockFlow* cb, RenderRegion* region) const +static LayoutUnit portionOfMarginNotConsumedByFloat(LayoutUnit childMargin, LayoutUnit contentSide, LayoutUnit offset) { - RenderRegion* containingBlockRegion = 0; - LayoutUnit logicalTopPosition = logicalTop(); - if (region) { - LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage() : LayoutUnit(); - logicalTopPosition = max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion); - containingBlockRegion = cb->clampToStartAndEndRegions(region); - } + if (childMargin <= 0) + return 0; + LayoutUnit contentSideWithMargin = contentSide + childMargin; + if (offset > contentSideWithMargin) + return childMargin; + return offset - contentSide; +} - LayoutUnit result = cb->availableLogicalWidthForLineInRegion(logicalTopPosition, false, containingBlockRegion) - childMarginStart - childMarginEnd; +LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlockFlow* cb) const +{ + LayoutUnit logicalTopPosition = logicalTop(); + LayoutUnit width = cb->availableLogicalWidthForLine(logicalTopPosition, false) - max<LayoutUnit>(0, childMarginStart) - max<LayoutUnit>(0, childMarginEnd); // We need to see if margins on either the start side or the end side can contain the floats in question. If they can, // then just using the line width is inaccurate. In the case where a float completely fits, we don't need to use the line // offset at all, but can instead push all the way to the content edge of the containing block. In the case where the float // doesn't fit, we can use the line offset, but we need to grow it by the margin to reflect the fact that the margin was // "consumed" by the float. Negative margins aren't consumed by the float, and so we ignore them. - if (childMarginStart > 0) { - LayoutUnit startContentSide = cb->startOffsetForContent(containingBlockRegion); - LayoutUnit startContentSideWithMargin = startContentSide + childMarginStart; - LayoutUnit startOffset = cb->startOffsetForLineInRegion(logicalTopPosition, false, containingBlockRegion); - if (startOffset > startContentSideWithMargin) - result += childMarginStart; - else - result += startOffset - startContentSide; - } - - if (childMarginEnd > 0) { - LayoutUnit endContentSide = cb->endOffsetForContent(containingBlockRegion); - LayoutUnit endContentSideWithMargin = endContentSide + childMarginEnd; - LayoutUnit endOffset = cb->endOffsetForLineInRegion(logicalTopPosition, false, containingBlockRegion); - if (endOffset > endContentSideWithMargin) - result += childMarginEnd; - else - result += endOffset - endContentSide; - } - - return result; + width += portionOfMarginNotConsumedByFloat(childMarginStart, cb->startOffsetForContent(), cb->startOffsetForLine(logicalTopPosition, false)); + width += portionOfMarginNotConsumedByFloat(childMarginEnd, cb->endOffsetForContent(), cb->endOffsetForLine(logicalTopPosition, false)); + return width; } LayoutUnit RenderBox::containingBlockLogicalWidthForContent() const @@ -1851,33 +1780,12 @@ LayoutUnit RenderBox::containingBlockLogicalHeightForContent(AvailableLogicalHei return cb->availableLogicalHeight(heightType); } -LayoutUnit RenderBox::containingBlockLogicalWidthForContentInRegion(RenderRegion* region) const +LayoutUnit RenderBox::containingBlockAvailableLineWidth() const { - if (!region) - return containingBlockLogicalWidthForContent(); - RenderBlock* cb = containingBlock(); - RenderRegion* containingBlockRegion = cb->clampToStartAndEndRegions(region); - // FIXME: It's unclear if a region's content should use the containing block's override logical width. - // If it should, the following line should call containingBlockLogicalWidthForContent. - LayoutUnit result = cb->availableLogicalWidth(); - RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(containingBlockRegion); - if (!boxInfo) - return result; - return max<LayoutUnit>(0, result - (cb->logicalWidth() - boxInfo->logicalWidth())); -} - -LayoutUnit RenderBox::containingBlockAvailableLineWidthInRegion(RenderRegion* region) const -{ - RenderBlock* cb = containingBlock(); - RenderRegion* containingBlockRegion = 0; - LayoutUnit logicalTopPosition = logicalTop(); - if (region) { - LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage() : LayoutUnit(); - logicalTopPosition = max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion); - containingBlockRegion = cb->clampToStartAndEndRegions(region); - } - return cb->availableLogicalWidthForLineInRegion(logicalTopPosition, false, containingBlockRegion, availableLogicalHeight(IncludeMarginBorderPadding)); + if (cb->isRenderBlockFlow()) + return toRenderBlockFlow(cb)->availableLogicalWidthForLine(logicalTop(), false, availableLogicalHeight(IncludeMarginBorderPadding)); + return 0; } LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const @@ -1909,9 +1817,9 @@ void RenderBox::mapLocalToContainer(const RenderLayerModelObject* repaintContain return; if (RenderView* v = view()) { - if (v->layoutStateEnabled() && !repaintContainer) { + if (v->canMapUsingLayoutStateForContainer(repaintContainer)) { LayoutState* layoutState = v->layoutState(); - LayoutSize offset = layoutState->m_paintOffset + locationOffset(); + LayoutSize offset = layoutState->paintOffset() + locationOffset(); if (style()->hasInFlowPosition() && layer()) offset += layer()->offsetForInFlowPosition(); transformState.move(offset); @@ -1962,7 +1870,7 @@ void RenderBox::mapLocalToContainer(const RenderLayerModelObject* repaintContain void RenderBox::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const { // We don't expect to be called during layout. - ASSERT(!view() || !view()->layoutStateEnabled()); + ASSERT(!view() || !view()->layoutStateCachedOffsetsEnabled()); bool isFixedPos = style()->position() == FixedPosition; bool hasTransform = hasLayer() && layer()->transform(); @@ -1976,13 +1884,9 @@ void RenderBox::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState RenderBoxModelObject::mapAbsoluteToLocalPoint(mode, transformState); } -LayoutSize RenderBox::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const +LayoutSize RenderBox::offsetFromContainer(const RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const { - // A region "has" boxes inside it without being their container. - // FIXME: change container() / containingBlock() to count for boxes being positioned relative to the region, not the - // FlowThread. This requires a separate patch as a simple test with such a change in container() causes 129 out of - // 337 regions tests to fail. - ASSERT(o == container() || o->isRenderRegion()); + ASSERT(o == container()); LayoutSize offset; if (isInFlowPositioned()) @@ -1990,46 +1894,55 @@ LayoutSize RenderBox::offsetFromContainer(RenderObject* o, const LayoutPoint& po if (!isInline() || isReplaced()) { if (!style()->hasOutOfFlowPosition() && o->hasColumns()) { - RenderBlock* block = toRenderBlock(o); + const RenderBlock* block = toRenderBlock(o); LayoutRect columnRect(frameRect()); block->adjustStartEdgeForWritingModeIncludingColumns(columnRect); offset += toSize(columnRect.location()); LayoutPoint columnPoint = block->flipForWritingModeIncludingColumns(point + offset); offset = toLayoutSize(block->flipForWritingModeIncludingColumns(toLayoutPoint(offset))); - o->adjustForColumns(offset, columnPoint); + offset += o->columnOffset(columnPoint); offset = block->flipForWritingMode(offset); if (offsetDependsOnPoint) *offsetDependsOnPoint = true; - } else + } else { offset += topLeftLocationOffset(); + if (o->isRenderFlowThread()) { + // So far the point has been in flow thread coordinates (i.e. as if everything in + // the fragmentation context lived in one tall single column). Convert it to a + // visual point now. + LayoutPoint pointInContainer = point + offset; + offset += o->columnOffset(pointInContainer); + if (offsetDependsOnPoint) + *offsetDependsOnPoint = true; + } + } } if (o->hasOverflowClip()) offset -= toRenderBox(o)->scrolledContentOffset(); if (style()->position() == AbsolutePosition && o->isInFlowPositioned() && o->isRenderInline()) - offset += toRenderInline(o)->offsetForInFlowPositionedInline(this); - - if (offsetDependsOnPoint) - *offsetDependsOnPoint |= o->isRenderFlowThread(); + offset += toRenderInline(o)->offsetForInFlowPositionedInline(*this); return offset; } InlineBox* RenderBox::createInlineBox() { - return new InlineBox(this); + return new InlineBox(*this); } void RenderBox::dirtyLineBoxes(bool fullLayout) { - if (m_inlineBoxWrapper) { + if (inlineBoxWrapper()) { if (fullLayout) { - m_inlineBoxWrapper->destroy(); - m_inlineBoxWrapper = 0; - } else - m_inlineBoxWrapper->dirtyLineBoxes(); + inlineBoxWrapper()->destroy(); + ASSERT(m_rareData); + m_rareData->m_inlineBoxWrapper = 0; + } else { + inlineBoxWrapper()->dirtyLineBoxes(); + } } } @@ -2042,8 +1955,8 @@ void RenderBox::positionLineBox(InlineBox* box) // The value is cached in the xPos of the box. We only need this value if // our object was inline originally, since otherwise it would have ended up underneath // the inlines. - RootInlineBox* root = box->root(); - root->block()->setStaticInlinePositionForChild(this, root->lineTopWithLeading(), LayoutUnit::fromFloatRound(box->logicalLeft())); + RootInlineBox& root = box->root(); + root.block().setStaticInlinePositionForChild(this, root.lineTopWithLeading(), LayoutUnit::fromFloatRound(box->logicalLeft())); if (style()->hasStaticInlinePosition(box->isHorizontal())) setChildNeedsLayout(MarkOnlyThis); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly. } else { @@ -2057,7 +1970,7 @@ void RenderBox::positionLineBox(InlineBox* box) } // Nuke the box. - box->remove(); + box->remove(DontMarkLineBoxes); box->destroy(); } else if (isReplaced()) { setLocation(roundedLayoutPoint(box->topLeft())); @@ -2067,42 +1980,34 @@ void RenderBox::positionLineBox(InlineBox* box) void RenderBox::deleteLineBoxWrapper() { - if (m_inlineBoxWrapper) { + if (inlineBoxWrapper()) { if (!documentBeingDestroyed()) - m_inlineBoxWrapper->remove(); - m_inlineBoxWrapper->destroy(); - m_inlineBoxWrapper = 0; + inlineBoxWrapper()->remove(); + inlineBoxWrapper()->destroy(); + ASSERT(m_rareData); + m_rareData->m_inlineBoxWrapper = 0; } } -LayoutRect RenderBox::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const +LayoutRect RenderBox::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const { - if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) + if (style()->visibility() != VISIBLE && enclosingLayer()->subtreeIsInvisible()) return LayoutRect(); LayoutRect r = visualOverflowRect(); RenderView* v = view(); - if (v) { + if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && v) { // FIXME: layoutDelta needs to be applied in parts before/after transforms and // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 r.move(v->layoutDelta()); } - if (style()) { - // We have to use maximalOutlineSize() because a child might have an outline - // that projects outside of our overflowRect. - if (v) { - ASSERT(style()->outlineSize() <= v->maximalOutlineSize()); - r.inflate(v->maximalOutlineSize()); - } - } - - computeRectForRepaint(repaintContainer, r); + mapRectToPaintInvalidationBacking(paintInvalidationContainer, r); return r; } -void RenderBox::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const +void RenderBox::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, bool fixed) const { // The rect we compute at each step is shifted by our x/y offset in the parent container's coordinate space. // Only when we cross a writing mode boundary will we have to possibly flipForWritingMode (to convert into a more appropriate @@ -2110,12 +2015,12 @@ void RenderBox::computeRectForRepaint(const RenderLayerModelObject* repaintConta // properly even during layout, since the rect remains flipped all the way until the end. // // RenderView::computeRectForRepaint then converts the rect to physical coordinates. We also convert to - // physical when we hit a repaintContainer boundary. Therefore the final rect returned is always in the - // physical coordinate space of the repaintContainer. + // physical when we hit a paintInvalidationContainer boundary. Therefore the final rect returned is always in the + // physical coordinate space of the paintInvalidationContainer. RenderStyle* styleToUse = style(); if (RenderView* v = view()) { // LayoutState is only valid for root-relative, non-fixed position repainting - if (v->layoutStateEnabled() && !repaintContainer && styleToUse->position() != FixedPosition) { + if (v->canMapUsingLayoutStateForContainer(paintInvalidationContainer) && styleToUse->position() != FixedPosition) { LayoutState* layoutState = v->layoutState(); if (layer() && layer()->transform()) @@ -2126,9 +2031,9 @@ void RenderBox::computeRectForRepaint(const RenderLayerModelObject* repaintConta rect.move(layer()->offsetForInFlowPosition()); rect.moveBy(location()); - rect.move(layoutState->m_paintOffset); - if (layoutState->m_clipped) - rect.intersect(layoutState->m_clipRect); + rect.move(layoutState->paintOffset()); + if (layoutState->isClipped()) + rect.intersect(layoutState->clipRect()); return; } } @@ -2136,14 +2041,14 @@ void RenderBox::computeRectForRepaint(const RenderLayerModelObject* repaintConta if (hasReflection()) rect.unite(reflectedRect(rect)); - if (repaintContainer == this) { - if (repaintContainer->style()->isFlippedBlocksWritingMode()) + if (paintInvalidationContainer == this) { + if (paintInvalidationContainer->style()->isFlippedBlocksWritingMode()) flipForWritingMode(rect); return; } bool containerSkipped; - RenderObject* o = container(repaintContainer, &containerSkipped); + RenderObject* o = container(paintInvalidationContainer, &containerSkipped); if (!o) return; @@ -2166,7 +2071,7 @@ void RenderBox::computeRectForRepaint(const RenderLayerModelObject* repaintConta fixed = true; if (position == AbsolutePosition && o->isInFlowPositioned() && o->isRenderInline()) { - topLeft += toRenderInline(o)->offsetForInFlowPositionedInline(this); + topLeft += toRenderInline(o)->offsetForInFlowPositionedInline(*this); } else if (styleToUse->hasInFlowPosition() && 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 @@ -2193,13 +2098,13 @@ void RenderBox::computeRectForRepaint(const RenderLayerModelObject* repaintConta } if (containerSkipped) { - // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates. - LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o); + // If the paintInvalidationContainer is below o, then we need to map the rect into paintInvalidationContainer's coordinates. + LayoutSize containerOffset = paintInvalidationContainer->offsetFromAncestorContainer(o); rect.move(-containerOffset); return; } - o->computeRectForRepaint(repaintContainer, rect, fixed); + o->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, fixed); } void RenderBox::repaintDuringLayoutIfMoved(const LayoutRect& oldRect) @@ -2209,10 +2114,10 @@ void RenderBox::repaintDuringLayoutIfMoved(const LayoutRect& oldRect) // The child moved. Invalidate the object's old and new positions. We have to do this // since the object may not have gotten a layout. m_frameRect = oldRect; - repaint(); + paintInvalidationForWholeRenderer(); repaintOverhangingFloats(true); m_frameRect = newRect; - repaint(); + paintInvalidationForWholeRenderer(); repaintOverhangingFloats(true); } } @@ -2224,7 +2129,7 @@ void RenderBox::repaintOverhangingFloats(bool) void RenderBox::updateLogicalWidth() { LogicalExtentComputedValues computedValues; - computeLogicalWidthInRegion(computedValues); + computeLogicalWidth(computedValues); setLogicalWidth(computedValues.m_extent); setLogicalLeft(computedValues.m_position); @@ -2238,25 +2143,22 @@ static float getMaxWidthListMarker(const RenderBox* renderer) ASSERT(renderer); Node* parentNode = renderer->generatingNode(); ASSERT(parentNode); - ASSERT(parentNode->hasTagName(olTag) || parentNode->hasTagName(ulTag)); + ASSERT(isHTMLOListElement(parentNode) || isHTMLUListElement(parentNode)); ASSERT(renderer->style()->textAutosizingMultiplier() != 1); #endif float maxWidth = 0; - for (RenderObject* child = renderer->firstChild(); child; child = child->nextSibling()) { + for (RenderObject* child = renderer->slowFirstChild(); child; child = child->nextSibling()) { if (!child->isListItem()) continue; RenderBox* listItem = toRenderBox(child); - for (RenderObject* itemChild = listItem->firstChild(); itemChild; itemChild = itemChild->nextSibling()) { + for (RenderObject* itemChild = listItem->slowFirstChild(); itemChild; itemChild = itemChild->nextSibling()) { if (!itemChild->isListMarker()) continue; RenderBox* itemMarker = toRenderBox(itemChild); - // FIXME: canDetermineWidthWithoutLayout expects us to use fixedOffsetWidth, which this code - // does not do! This check is likely wrong. - if (!itemMarker->canDetermineWidthWithoutLayout() && itemMarker->needsLayout()) { - // Make sure to compute the autosized width. + // Make sure to compute the autosized width. + if (itemMarker->needsLayout()) itemMarker->layout(); - } maxWidth = max<float>(maxWidth, toRenderListMarker(itemMarker)->logicalWidth().toFloat()); break; } @@ -2264,7 +2166,7 @@ static float getMaxWidthListMarker(const RenderBox* renderer) return maxWidth; } -void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& computedValues, RenderRegion* region) const +void RenderBox::computeLogicalWidth(LogicalExtentComputedValues& computedValues) const { computedValues.m_extent = logicalWidth(); computedValues.m_position = logicalLeft(); @@ -2274,7 +2176,7 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute if (isOutOfFlowPositioned()) { // FIXME: This calculation is not patched for block-flow yet. // https://bugs.webkit.org/show_bug.cgi?id=46500 - computePositionedLogicalWidth(computedValues, region); + computePositionedLogicalWidth(computedValues); return; } @@ -2301,16 +2203,15 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute Length logicalWidthLength = treatAsReplaced ? Length(computeReplacedLogicalWidth(), Fixed) : styleToUse->logicalWidth(); RenderBlock* cb = containingBlock(); - LayoutUnit containerLogicalWidth = max<LayoutUnit>(0, containingBlockLogicalWidthForContentInRegion(region)); + LayoutUnit containerLogicalWidth = max<LayoutUnit>(0, containingBlockLogicalWidthForContent()); bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode(); if (isInline() && !isInlineBlockOrInlineTable()) { // just calculate margins - RenderView* renderView = view(); - computedValues.m_margins.m_start = minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth, renderView); - computedValues.m_margins.m_end = minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth, renderView); + computedValues.m_margins.m_start = minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth); + computedValues.m_margins.m_end = minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth); if (treatAsReplaced) - computedValues.m_extent = max<LayoutUnit>(floatValueForLength(logicalWidthLength, 0, 0) + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth()); + computedValues.m_extent = max<LayoutUnit>(floatValueForLength(logicalWidthLength, 0) + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth()); return; } @@ -2321,24 +2222,13 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute LayoutUnit containerWidthInInlineDirection = containerLogicalWidth; if (hasPerpendicularContainingBlock) containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight(); - LayoutUnit preferredWidth = computeLogicalWidthInRegionUsing(MainOrPreferredSize, styleToUse->logicalWidth(), containerWidthInInlineDirection, cb, region); - computedValues.m_extent = constrainLogicalWidthInRegionByMinMax(preferredWidth, containerWidthInInlineDirection, cb, region); + LayoutUnit preferredWidth = computeLogicalWidthUsing(MainOrPreferredSize, styleToUse->logicalWidth(), containerWidthInInlineDirection, cb); + computedValues.m_extent = constrainLogicalWidthByMinMax(preferredWidth, containerWidthInInlineDirection, cb); } // Margin calculations. - if (hasPerpendicularContainingBlock || isFloating() || isInline()) { - RenderView* renderView = view(); - computedValues.m_margins.m_start = minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth, renderView); - computedValues.m_margins.m_end = minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth, renderView); - } else { - LayoutUnit containerLogicalWidthForAutoMargins = containerLogicalWidth; - if (avoidsFloats() && cb->containsFloats()) - containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(region); - bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection(); - computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, computedValues.m_extent, - hasInvertedDirection ? computedValues.m_margins.m_end : computedValues.m_margins.m_start, - hasInvertedDirection ? computedValues.m_margins.m_start : computedValues.m_margins.m_end); - } + computeMarginsForDirection(InlineDirection, cb, containerLogicalWidth, computedValues.m_extent, computedValues.m_margins.m_start, + computedValues.m_margins.m_end, style()->marginStart(), style()->marginEnd()); if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (computedValues.m_extent + computedValues.m_margins.m_start + computedValues.m_margins.m_end) && !isFloating() && !isInline() && !cb->isFlexibleBoxIncludingDeprecated() && !cb->isRenderGrid()) { @@ -2352,7 +2242,7 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute if (styleToUse->textAutosizingMultiplier() != 1 && styleToUse->marginStart().type() == Fixed) { Node* parentNode = generatingNode(); - if (parentNode && (parentNode->hasTagName(olTag) || parentNode->hasTagName(ulTag))) { + if (parentNode && (isHTMLOListElement(*parentNode) || isHTMLUListElement(*parentNode))) { // Make sure the markers in a list are properly positioned (i.e. not chopped off) when autosized. const float adjustedMargin = (1 - 1.0 / styleToUse->textAutosizingMultiplier()) * getMaxWidthListMarker(this); bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection(); @@ -2373,13 +2263,12 @@ LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth) con LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const { - RenderView* renderView = view(); - marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth, renderView); - marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth, renderView); + marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth); + marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth); return availableLogicalWidth - marginStart - marginEnd; } -LayoutUnit RenderBox::computeIntrinsicLogicalWidthUsing(Length logicalWidthLength, LayoutUnit availableLogicalWidth, LayoutUnit borderAndPadding) const +LayoutUnit RenderBox::computeIntrinsicLogicalWidthUsing(const Length& logicalWidthLength, LayoutUnit availableLogicalWidth, LayoutUnit borderAndPadding) const { if (logicalWidthLength.type() == FillAvailable) return fillAvailableMeasure(availableLogicalWidth); @@ -2404,12 +2293,11 @@ LayoutUnit RenderBox::computeIntrinsicLogicalWidthUsing(Length logicalWidthLengt return 0; } -LayoutUnit RenderBox::computeLogicalWidthInRegionUsing(SizeType widthType, Length logicalWidth, LayoutUnit availableLogicalWidth, - const RenderBlock* cb, RenderRegion* region) const +LayoutUnit RenderBox::computeLogicalWidthUsing(SizeType widthType, const Length& logicalWidth, LayoutUnit availableLogicalWidth, const RenderBlock* cb) const { if (!logicalWidth.isIntrinsicOrAuto()) { // FIXME: If the containing block flow is perpendicular to our direction we need to use the available logical height instead. - return adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, availableLogicalWidth, view())); + return adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, availableLogicalWidth)); } if (logicalWidth.isIntrinsic()) @@ -2420,9 +2308,9 @@ LayoutUnit RenderBox::computeLogicalWidthInRegionUsing(SizeType widthType, Lengt LayoutUnit logicalWidthResult = fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd); if (shrinkToAvoidFloats() && cb->containsFloats()) - logicalWidthResult = min(logicalWidthResult, shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, toRenderBlockFlow(cb), region)); + logicalWidthResult = min(logicalWidthResult, shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, toRenderBlockFlow(cb))); - if (widthType == MainOrPreferredSize && sizesLogicalWidthToFitContent(widthType)) + if (widthType == MainOrPreferredSize && sizesLogicalWidthToFitContent(logicalWidth)) return max(minPreferredLogicalWidth(), min(maxPreferredLogicalWidth(), logicalWidthResult)); return logicalWidthResult; } @@ -2435,7 +2323,7 @@ static bool columnFlexItemHasStretchAlignment(const RenderObject* flexitem) ASSERT(parent->style()->isColumnFlexDirection()); if (flexitem->style()->marginStart().isAuto() || flexitem->style()->marginEnd().isAuto()) return false; - return flexitem->style()->alignSelf() == AlignStretch || (flexitem->style()->alignSelf() == AlignAuto && parent->style()->alignItems() == AlignStretch); + return flexitem->style()->alignSelf() == ItemPositionStretch || (flexitem->style()->alignSelf() == ItemPositionAuto && parent->style()->alignItems() == ItemPositionStretch); } static bool isStretchingColumnFlexItem(const RenderObject* flexitem) @@ -2450,16 +2338,13 @@ static bool isStretchingColumnFlexItem(const RenderObject* flexitem) return false; } -bool RenderBox::sizesLogicalWidthToFitContent(SizeType widthType) const +bool RenderBox::sizesLogicalWidthToFitContent(const Length& logicalWidth) const { // Marquees in WinIE are like a mixture of blocks and inline-blocks. They size as though they're blocks, // but they allow text to sit on the same line as the marquee. if (isFloating() || (isInlineBlockOrInlineTable() && !isMarquee())) return true; - // This code may look a bit strange. Basically width:intrinsic should clamp the size when testing both - // min-width and width. max-width is only clamped if it is also intrinsic. - Length logicalWidth = (widthType == MaxSize) ? style()->logicalMaxWidth() : style()->logicalWidth(); if (logicalWidth.type() == Intrinsic) return true; @@ -2496,7 +2381,7 @@ bool RenderBox::sizesLogicalWidthToFitContent(SizeType widthType) const // stretching column flexbox. // FIXME: Think about block-flow here. // https://bugs.webkit.org/show_bug.cgi?id=46473 - if (logicalWidth.type() == Auto && !isStretchingColumnFlexItem(this) && autoWidthShouldFitContent()) + if (logicalWidth.isAuto() && !isStretchingColumnFlexItem(this) && autoWidthShouldFitContent()) return true; if (isHorizontalWritingMode() != containingBlock()->isHorizontalWritingMode()) @@ -2507,24 +2392,26 @@ bool RenderBox::sizesLogicalWidthToFitContent(SizeType widthType) const bool RenderBox::autoWidthShouldFitContent() const { - if (node() && (node()->hasTagName(inputTag) || node()->hasTagName(selectTag) || node()->hasTagName(buttonTag) - || isHTMLTextAreaElement(node()) || node()->hasTagName(legendTag))) - return true; - - return false; + return node() && (isHTMLInputElement(*node()) || isHTMLSelectElement(*node()) || isHTMLButtonElement(*node()) + || isHTMLTextAreaElement(*node()) || (isHTMLLegendElement(*node()) && !style()->hasOutOfFlowPosition())); } -void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const +void RenderBox::computeMarginsForDirection(MarginDirection flowDirection, const RenderBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd, Length marginStartLength, Length marginEndLength) const { - const RenderStyle* containingBlockStyle = containingBlock->style(); - Length marginStartLength = style()->marginStartUsing(containingBlockStyle); - Length marginEndLength = style()->marginEndUsing(containingBlockStyle); - RenderView* renderView = view(); + if (flowDirection == BlockDirection || isFloating() || isInline()) { + if (isTableCell() && flowDirection == BlockDirection) { + // FIXME: Not right if we allow cells to have different directionality than the table. If we do allow this, though, + // we may just do it with an extra anonymous block inside the cell. + marginStart = 0; + marginEnd = 0; + return; + } - if (isFloating() || isInline()) { + // Margins are calculated with respect to the logical width of + // the containing block (8.3) // Inline blocks/tables and floats don't have their margins increased. - marginStart = minimumValueForLength(marginStartLength, containerWidth, renderView); - marginEnd = minimumValueForLength(marginEndLength, containerWidth, renderView); + marginStart = minimumValueForLength(marginStartLength, containerWidth); + marginEnd = minimumValueForLength(marginEndLength, containerWidth); return; } @@ -2538,129 +2425,53 @@ void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, Layo marginEndLength.setValue(0); } - // Case One: The object is being centered in the containing block's available logical width. - if ((marginStartLength.isAuto() && marginEndLength.isAuto() && childWidth < containerWidth) - || (!marginStartLength.isAuto() && !marginEndLength.isAuto() && containingBlock->style()->textAlign() == WEBKIT_CENTER)) { + LayoutUnit marginStartWidth = minimumValueForLength(marginStartLength, containerWidth); + LayoutUnit marginEndWidth = minimumValueForLength(marginEndLength, containerWidth); + + LayoutUnit availableWidth = containerWidth; + if (avoidsFloats() && containingBlock->containsFloats()) { + availableWidth = containingBlockAvailableLineWidth(); + if (shrinkToAvoidFloats() && availableWidth < containerWidth) { + marginStart = max<LayoutUnit>(0, marginStartWidth); + marginEnd = max<LayoutUnit>(0, marginEndWidth); + } + } + + // CSS 2.1 (10.3.3): "If 'width' is not 'auto' and 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + // (plus any of 'margin-left' or 'margin-right' that are not 'auto') is larger than the width of the containing block, then any 'auto' + // values for 'margin-left' or 'margin-right' are, for the following rules, treated as zero. + LayoutUnit marginBoxWidth = childWidth + (!style()->width().isAuto() ? marginStartWidth + marginEndWidth : LayoutUnit()); + + // CSS 2.1: "If both 'margin-left' and 'margin-right' are 'auto', their used values are equal. This horizontally centers the element + // with respect to the edges of the containing block." + const RenderStyle* containingBlockStyle = containingBlock->style(); + if ((marginStartLength.isAuto() && marginEndLength.isAuto() && marginBoxWidth < availableWidth) + || (!marginStartLength.isAuto() && !marginEndLength.isAuto() && containingBlockStyle->textAlign() == WEBKIT_CENTER)) { // Other browsers center the margin box for align=center elements so we match them here. - LayoutUnit marginStartWidth = minimumValueForLength(marginStartLength, containerWidth, renderView); - LayoutUnit marginEndWidth = minimumValueForLength(marginEndLength, containerWidth, renderView); - LayoutUnit centeredMarginBoxStart = max<LayoutUnit>(0, (containerWidth - childWidth - marginStartWidth - marginEndWidth) / 2); + LayoutUnit centeredMarginBoxStart = max<LayoutUnit>(0, (availableWidth - childWidth - marginStartWidth - marginEndWidth) / 2); marginStart = centeredMarginBoxStart + marginStartWidth; - marginEnd = containerWidth - childWidth - marginStart + marginEndWidth; + marginEnd = availableWidth - childWidth - marginStart + marginEndWidth; return; } - // Case Two: The object is being pushed to the start of the containing block's available logical width. - if (marginEndLength.isAuto() && childWidth < containerWidth) { - marginStart = valueForLength(marginStartLength, containerWidth, renderView); - marginEnd = containerWidth - childWidth - marginStart; + // CSS 2.1: "If there is exactly one value specified as 'auto', its used value follows from the equality." + if (marginEndLength.isAuto() && marginBoxWidth < availableWidth) { + marginStart = marginStartWidth; + marginEnd = availableWidth - childWidth - marginStart; return; } - // Case Three: The object is being pushed to the end of the containing block's available logical width. bool pushToEndFromTextAlign = !marginEndLength.isAuto() && ((!containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_LEFT) || (containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_RIGHT)); - if ((marginStartLength.isAuto() && childWidth < containerWidth) || pushToEndFromTextAlign) { - marginEnd = valueForLength(marginEndLength, containerWidth, renderView); - marginStart = containerWidth - childWidth - marginEnd; + if ((marginStartLength.isAuto() && marginBoxWidth < availableWidth) || pushToEndFromTextAlign) { + marginEnd = marginEndWidth; + marginStart = availableWidth - childWidth - marginEnd; 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. - marginStart = minimumValueForLength(marginStartLength, containerWidth, renderView); - marginEnd = minimumValueForLength(marginEndLength, containerWidth, renderView); -} - -RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, RenderBoxRegionInfoFlags cacheFlag) const -{ - // Make sure nobody is trying to call this with a null region. - if (!region) - return 0; - - // If we have computed our width in this region already, it will be cached, and we can - // just return it. - RenderBoxRegionInfo* boxInfo = region->renderBoxRegionInfo(this); - if (boxInfo && cacheFlag == CacheRenderBoxRegionInfo) - return boxInfo; - - // No cached value was found, so we have to compute our insets in this region. - // FIXME: For now we limit this computation to normal RenderBlocks. Future patches will expand - // support to cover all boxes. - RenderFlowThread* flowThread = flowThreadContainingBlock(); - if (isRenderFlowThread() || !flowThread || !canHaveBoxInfoInRegion() || flowThread->style()->writingMode() != style()->writingMode()) - return 0; - - LogicalExtentComputedValues computedValues; - computeLogicalWidthInRegion(computedValues, region); - - // Now determine the insets based off where this object is supposed to be positioned. - RenderBlock* cb = containingBlock(); - RenderRegion* clampedContainingBlockRegion = cb->clampToStartAndEndRegions(region); - RenderBoxRegionInfo* containingBlockInfo = cb->renderBoxRegionInfo(clampedContainingBlockRegion); - LayoutUnit containingBlockLogicalWidth = cb->logicalWidth(); - LayoutUnit containingBlockLogicalWidthInRegion = containingBlockInfo ? containingBlockInfo->logicalWidth() : containingBlockLogicalWidth; - - LayoutUnit marginStartInRegion = computedValues.m_margins.m_start; - LayoutUnit startMarginDelta = marginStartInRegion - marginStart(); - LayoutUnit logicalWidthInRegion = computedValues.m_extent; - LayoutUnit logicalLeftInRegion = computedValues.m_position; - LayoutUnit widthDelta = logicalWidthInRegion - logicalWidth(); - LayoutUnit logicalLeftDelta = isOutOfFlowPositioned() ? logicalLeftInRegion - logicalLeft() : startMarginDelta; - LayoutUnit logicalRightInRegion = containingBlockLogicalWidthInRegion - (logicalLeftInRegion + logicalWidthInRegion); - LayoutUnit oldLogicalRight = containingBlockLogicalWidth - (logicalLeft() + logicalWidth()); - LayoutUnit logicalRightDelta = isOutOfFlowPositioned() ? logicalRightInRegion - oldLogicalRight : startMarginDelta; - - LayoutUnit logicalLeftOffset = 0; - - if (!isOutOfFlowPositioned() && avoidsFloats() && cb->containsFloats()) { - LayoutUnit startPositionDelta = cb->computeStartPositionDeltaForChildAvoidingFloats(this, marginStartInRegion, region); - if (cb->style()->isLeftToRightDirection()) - logicalLeftDelta += startPositionDelta; - else - logicalRightDelta += startPositionDelta; - } - - if (cb->style()->isLeftToRightDirection()) - logicalLeftOffset += logicalLeftDelta; - else - logicalLeftOffset -= (widthDelta + logicalRightDelta); - - LayoutUnit logicalRightOffset = logicalWidth() - (logicalLeftOffset + logicalWidthInRegion); - bool isShifted = (containingBlockInfo && containingBlockInfo->isShifted()) - || (style()->isLeftToRightDirection() && logicalLeftOffset) - || (!style()->isLeftToRightDirection() && logicalRightOffset); - - // FIXME: Although it's unlikely, these boxes can go outside our bounds, and so we will need to incorporate them into overflow. - if (cacheFlag == CacheRenderBoxRegionInfo) - return region->setRenderBoxRegionInfo(this, logicalLeftOffset, logicalWidthInRegion, isShifted); - return new RenderBoxRegionInfo(logicalLeftOffset, logicalWidthInRegion, isShifted); -} - -static bool shouldFlipBeforeAfterMargins(const RenderStyle* containingBlockStyle, const RenderStyle* childStyle) -{ - ASSERT(containingBlockStyle->isHorizontalWritingMode() != childStyle->isHorizontalWritingMode()); - WritingMode childWritingMode = childStyle->writingMode(); - bool shouldFlip = false; - switch (containingBlockStyle->writingMode()) { - case TopToBottomWritingMode: - shouldFlip = (childWritingMode == RightToLeftWritingMode); - break; - case BottomToTopWritingMode: - shouldFlip = (childWritingMode == RightToLeftWritingMode); - break; - case RightToLeftWritingMode: - shouldFlip = (childWritingMode == BottomToTopWritingMode); - break; - case LeftToRightWritingMode: - shouldFlip = (childWritingMode == BottomToTopWritingMode); - break; - } - - if (!containingBlockStyle->isLeftToRightDirection()) - shouldFlip = !shouldFlip; - - return shouldFlip; + // Either no auto margins, or our margin box width is >= the container width, auto margins will just turn into 0. + marginStart = marginStartWidth; + marginEnd = marginEndWidth; } void RenderBox::updateLogicalHeight() @@ -2690,23 +2501,20 @@ void RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logica computePositionedLogicalHeight(computedValues); else { RenderBlock* cb = containingBlock(); - bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode(); - if (!hasPerpendicularContainingBlock) { - bool shouldFlipBeforeAfter = cb->style()->writingMode() != style()->writingMode(); - computeBlockDirectionMargins(cb, - shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before, - shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after); - } + // If we are perpendicular to our containing block then we need to resolve our block-start and block-end margins so that if they + // are 'auto' we are centred or aligned within the inline flow containing block: this is done by computing the margins as though they are inline. + // Note that as this is the 'sizing phase' we are using our own writing mode rather than the containing block's. We use the containing block's + // writing mode when figuring out the block-direction margins for positioning in |computeAndSetBlockDirectionMargins| (i.e. margin collapsing etc.). + // See http://www.w3.org/TR/2014/CR-css-writing-modes-3-20140320/#orthogonal-flows + MarginDirection flowDirection = isHorizontalWritingMode() != cb->isHorizontalWritingMode() ? InlineDirection : BlockDirection; // For tables, calculate margins only. if (isTable()) { - if (hasPerpendicularContainingBlock) { - bool shouldFlipBeforeAfter = shouldFlipBeforeAfterMargins(cb->style(), style()); - computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), computedValues.m_extent, - shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before, - shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after); - } + // FIXME: RenderTable::layout() calls updateLogicalHeight() when an empty table has no height yet, so auto margins can come out wrong here when + // we are perpendicular to our containing block. + computeMarginsForDirection(flowDirection, cb, containingBlockLogicalWidthForContent(), computedValues.m_extent, computedValues.m_margins.m_before, + computedValues.m_margins.m_after, style()->marginBefore(), style()->marginAfter()); return; } @@ -2733,8 +2541,7 @@ void RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logica // Block children of horizontal flexible boxes fill the height of the box. // FIXME: Account for block-flow in flexible boxes. // https://bugs.webkit.org/show_bug.cgi?id=46418 - if (h.isAuto() && parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL - && parent()->isStretchingChildren()) { + if (h.isAuto() && inHorizontalBox && toRenderDeprecatedFlexibleBox(parent())->isStretchingChildren()) { h = Length(parentBox()->contentLogicalHeight() - marginBefore() - marginAfter() - borderAndPaddingLogicalHeight(), Fixed); checkMinMaxHeight = false; } @@ -2754,13 +2561,8 @@ void RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logica } computedValues.m_extent = heightResult; - - if (hasPerpendicularContainingBlock) { - bool shouldFlipBeforeAfter = shouldFlipBeforeAfterMargins(cb->style(), style()); - computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), heightResult, - shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before, - shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after); - } + computeMarginsForDirection(flowDirection, cb, containingBlockLogicalWidthForContent(), computedValues.m_extent, computedValues.m_margins.m_before, + computedValues.m_margins.m_after, style()->marginBefore(), style()->marginAfter()); } // WinIE quirk: The <html> block always fills the entire canvas in quirks mode. The <body> always fills the @@ -2769,11 +2571,11 @@ void RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logica // height since we don't set a height in RenderView when we're printing. So without this quirk, the // height has nothing to be a percentage of, and it ends up being 0. That is bad. bool paginatedContentNeedsBaseHeight = document().printing() && h.isPercent() - && (isRoot() || (isBody() && document().documentElement()->renderer()->style()->logicalHeight().isPercent())) && !isInline(); + && (isDocumentElement() || (isBody() && document().documentElement()->renderer()->style()->logicalHeight().isPercent())) && !isInline(); if (stretchesToViewport() || paginatedContentNeedsBaseHeight) { LayoutUnit margins = collapsedMarginBefore() + collapsedMarginAfter(); - LayoutUnit visibleHeight = viewLogicalHeightForPercentages(); - if (isRoot()) + LayoutUnit visibleHeight = view()->viewLogicalHeightForPercentages(); + if (isDocumentElement()) computedValues.m_extent = max(computedValues.m_extent, visibleHeight - margins); else { LayoutUnit marginsBordersPadding = margins + parentBox()->marginBefore() + parentBox()->marginAfter() + parentBox()->borderAndPaddingLogicalHeight(); @@ -2782,13 +2584,6 @@ void RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logica } } -LayoutUnit RenderBox::viewLogicalHeightForPercentages() const -{ - if (document().printing()) - return static_cast<LayoutUnit>(view()->pageLogicalHeight()); - return view()->viewLogicalHeight(); -} - LayoutUnit RenderBox::computeLogicalHeightUsing(const Length& height, LayoutUnit intrinsicContentHeight) const { LayoutUnit logicalHeight = computeContentAndScrollbarLogicalHeightUsing(height, intrinsicContentHeight); @@ -2805,7 +2600,7 @@ LayoutUnit RenderBox::computeContentLogicalHeight(const Length& height, LayoutUn return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight()); } -LayoutUnit RenderBox::computeIntrinsicLogicalContentHeightUsing(Length logicalHeightLength, LayoutUnit intrinsicContentHeight, LayoutUnit borderAndPadding) const +LayoutUnit RenderBox::computeIntrinsicLogicalContentHeightUsing(const Length& logicalHeightLength, LayoutUnit intrinsicContentHeight, LayoutUnit borderAndPadding) const { // FIXME(cbiesinger): The css-sizing spec is considering changing what min-content/max-content should resolve to. // If that happens, this code will have to change. @@ -2835,13 +2630,16 @@ LayoutUnit RenderBox::computeContentAndScrollbarLogicalHeightUsing(const Length& return height.value(); if (height.isPercent()) return computePercentageLogicalHeight(height); - if (height.isViewportPercentage()) - return valueForLength(height, 0, view()); return -1; } bool RenderBox::skipContainingBlockForPercentHeightCalculation(const RenderBox* containingBlock) const { + // Flow threads for multicol or paged overflow should be skipped. They are invisible to the DOM, + // and percent heights of children should be resolved against the multicol or paged container. + if (containingBlock->isRenderFlowThread()) + return true; + // For quirks mode and anonymous blocks, we skip auto-height containingBlocks when computing percentages. // For standards mode, we treat the percentage as auto if it has an auto-height containing block. if (!document().inQuirksMode() && !containingBlock->isAnonymousBlock()) @@ -2858,13 +2656,13 @@ LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const const RenderBox* containingBlockChild = this; LayoutUnit rootMarginBorderPaddingHeight = 0; while (!cb->isRenderView() && skipContainingBlockForPercentHeightCalculation(cb)) { - if (cb->isBody() || cb->isRoot()) + if (cb->isBody() || cb->isDocumentElement()) rootMarginBorderPaddingHeight += cb->marginBefore() + cb->marginAfter() + cb->borderAndPaddingLogicalHeight(); skippedAutoHeightContainingBlock = true; containingBlockChild = cb; cb = cb->containingBlock(); - cb->addPercentHeightDescendant(const_cast<RenderBox*>(this)); } + cb->addPercentHeightDescendant(const_cast<RenderBox*>(this)); RenderStyle* cbstyle = cb->style(); @@ -2914,17 +2712,6 @@ LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const LayoutUnit contentBoxHeight = cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight(), -1); availableHeight = max<LayoutUnit>(0, contentBoxHeight); } - } else if (cbstyle->logicalHeight().isViewportPercentage()) { - LayoutUnit heightWithScrollbar = valueForLength(cbstyle->logicalHeight(), 0, view()); - if (heightWithScrollbar != -1) { - LayoutUnit contentBoxHeightWithScrollbar = cb->adjustContentBoxLogicalHeightForBoxSizing(heightWithScrollbar); - // We need to adjust for min/max height because this method does not - // handle the min/max of the current block, its caller does. So the - // return value from the recursive call will not have been adjusted - // yet. - LayoutUnit contentBoxHeight = cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight(), -1); - availableHeight = max<LayoutUnit>(0, contentBoxHeight); - } } else if (isOutOfFlowPositionedWithSpecifiedHeight) { // Don't allow this to affect the block' height() member variable, since this // can get called while the block is still laying out its kids. @@ -2932,7 +2719,7 @@ LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const cb->computeLogicalHeight(cb->logicalHeight(), 0, computedValues); availableHeight = computedValues.m_extent - cb->borderAndPaddingLogicalHeight() - cb->scrollbarLogicalHeight(); } else if (cb->isRenderView()) - availableHeight = viewLogicalHeightForPercentages(); + availableHeight = view()->viewLogicalHeightForPercentages(); if (availableHeight == -1) return availableHeight; @@ -2963,7 +2750,7 @@ LayoutUnit RenderBox::computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUni return max(minLogicalWidth, min(logicalWidth, maxLogicalWidth)); } -LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(Length logicalWidth) const +LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(const Length& logicalWidth) const { switch (logicalWidth.type()) { case Fixed: @@ -2974,11 +2761,6 @@ LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(Length logicalWidth) cons LayoutUnit availableLogicalWidth = 0; return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth(); } - case ViewportPercentageWidth: - case ViewportPercentageHeight: - case ViewportPercentageMin: - case ViewportPercentageMax: - return adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, 0, view())); case FitContent: case FillAvailable: case Percent: @@ -2994,14 +2776,17 @@ LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(Length logicalWidth) cons return computeIntrinsicLogicalWidthUsing(logicalWidth, cw, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth(); if (cw > 0 || (!cw && (containerLogicalWidth.isFixed() || containerLogicalWidth.isPercent()))) return adjustContentBoxLogicalWidthForBoxSizing(minimumValueForLength(logicalWidth, cw)); + return 0; } - // fall through case Intrinsic: case MinIntrinsic: case Auto: - case ExtendToZoom: case Undefined: return intrinsicLogicalWidth(); + case ExtendToZoom: + case DeviceWidth: + case DeviceHeight: + break; } ASSERT_NOT_REACHED(); @@ -3020,7 +2805,7 @@ LayoutUnit RenderBox::computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutU return max(minLogicalHeight, min(logicalHeight, maxLogicalHeight)); } -LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) const +LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(const Length& logicalHeight) const { switch (logicalHeight.type()) { case Fixed: @@ -3029,10 +2814,10 @@ LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) co case Calculated: { RenderObject* cb = isOutOfFlowPositioned() ? container() : containingBlock(); - while (cb->isAnonymous()) { + while (cb->isAnonymous()) cb = cb->containingBlock(); + if (cb->isRenderBlock()) toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this)); - } // FIXME: This calculation is not patched for block-flow yet. // https://bugs.webkit.org/show_bug.cgi?id=46500 @@ -3072,11 +2857,6 @@ LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) co } return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, availableHeight)); } - case ViewportPercentageWidth: - case ViewportPercentageHeight: - case ViewportPercentageMin: - case ViewportPercentageMax: - return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, 0, view())); case MinContent: case MaxContent: case FitContent: @@ -3135,35 +2915,20 @@ LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h, AvailableLogi return availableHeight; } -void RenderBox::computeBlockDirectionMargins(const RenderBlock* containingBlock, LayoutUnit& marginBefore, LayoutUnit& marginAfter) const -{ - if (isTableCell()) { - // FIXME: Not right if we allow cells to have different directionality than the table. If we do allow this, though, - // we may just do it with an extra anonymous block inside the cell. - marginBefore = 0; - marginAfter = 0; - return; - } - - // 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(); - marginBefore = minimumValueForLength(style()->marginBeforeUsing(containingBlockStyle), cw, renderView); - marginAfter = minimumValueForLength(style()->marginAfterUsing(containingBlockStyle), cw, renderView); -} - void RenderBox::computeAndSetBlockDirectionMargins(const RenderBlock* containingBlock) { LayoutUnit marginBefore; LayoutUnit marginAfter; - computeBlockDirectionMargins(containingBlock, marginBefore, marginAfter); + computeMarginsForDirection(BlockDirection, containingBlock, containingBlockLogicalWidthForContent(), logicalHeight(), marginBefore, marginAfter, + style()->marginBeforeUsing(containingBlock->style()), + style()->marginAfterUsing(containingBlock->style())); + // Note that in this 'positioning phase' of the layout we are using the containing block's writing mode rather than our own when calculating margins. + // See http://www.w3.org/TR/2014/CR-css-writing-modes-3-20140320/#orthogonal-flows containingBlock->setMarginBeforeForChild(this, marginBefore); containingBlock->setMarginAfterForChild(this, marginAfter); } -LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, RenderRegion* region, bool checkForPerpendicularWritingMode) const +LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const { if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode()) return containingBlockLogicalHeightForPositioned(containingBlock, false); @@ -3177,30 +2942,8 @@ LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxMo } } - if (containingBlock->isBox()) { - RenderFlowThread* flowThread = flowThreadContainingBlock(); - if (!flowThread) - return toRenderBox(containingBlock)->clientLogicalWidth(); - - const RenderBlock* cb = toRenderBlock(containingBlock); - RenderBoxRegionInfo* boxInfo = 0; - if (!region) { - if (containingBlock->isRenderFlowThread() && !checkForPerpendicularWritingMode) - return toRenderFlowThread(containingBlock)->contentLogicalWidthOfFirstRegion(); - if (isWritingModeRoot()) { - LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage(); - RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset); - if (cbRegion) { - cbRegion = cb->clampToStartAndEndRegions(cbRegion); - boxInfo = cb->renderBoxRegionInfo(cbRegion); - } - } - } else if (region && flowThread->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode()) { - RenderRegion* containingBlockRegion = cb->clampToStartAndEndRegions(region); - boxInfo = cb->renderBoxRegionInfo(containingBlockRegion); - } - return (boxInfo) ? max<LayoutUnit>(0, cb->clientLogicalWidth() - (cb->logicalWidth() - boxInfo->logicalWidth())) : cb->clientLogicalWidth(); - } + if (containingBlock->isBox()) + return toRenderBox(containingBlock)->clientLogicalWidth(); ASSERT(containingBlock->isRenderInline() && containingBlock->isInFlowPositioned()); @@ -3228,7 +2971,7 @@ LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxMo LayoutUnit RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const { if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode()) - return containingBlockLogicalWidthForPositioned(containingBlock, 0, false); + return containingBlockLogicalWidthForPositioned(containingBlock, false); // Use viewport as container for top-level fixed-position elements. if (style()->position() == FixedPosition && containingBlock->isRenderView()) { @@ -3240,12 +2983,9 @@ LayoutUnit RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxM } if (containingBlock->isBox()) { - const RenderBlock* cb = toRenderBlock(containingBlock); - LayoutUnit result = cb->clientLogicalHeight(); - RenderFlowThread* flowThread = flowThreadContainingBlock(); - if (flowThread && containingBlock->isRenderFlowThread() && flowThread->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode()) - return toRenderFlowThread(containingBlock)->contentLogicalHeightOfFirstRegion(); - return result; + const RenderBlock* cb = containingBlock->isRenderBlock() ? + toRenderBlock(containingBlock) : containingBlock->containingBlock(); + return cb->clientLogicalHeight(); } ASSERT(containingBlock->isRenderInline() && containingBlock->isInFlowPositioned()); @@ -3268,7 +3008,7 @@ LayoutUnit RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxM return heightResult; } -static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRight, const RenderBox* child, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalWidth, RenderRegion* region) +static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRight, const RenderBox* child, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalWidth) { if (!logicalLeft.isAuto() || !logicalRight.isAuto()) return; @@ -3281,13 +3021,6 @@ static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRigh staticPosition += toRenderBox(curr)->logicalLeft(); if (toRenderBox(curr)->isRelPositioned()) staticPosition += toRenderBox(curr)->relativePositionOffset().width(); - if (region && curr->isRenderBlock()) { - const RenderBlock* cb = toRenderBlock(curr); - region = cb->clampToStartAndEndRegions(region); - RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region); - if (boxInfo) - staticPosition += boxInfo->logicalLeft(); - } } else if (curr->isInline()) { if (curr->isRelPositioned()) { if (!curr->style()->logicalLeft().isAuto()) @@ -3310,17 +3043,6 @@ static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRigh } if (curr == enclosingBox) staticPosition -= enclosingBox->logicalWidth(); - if (region && curr->isRenderBlock()) { - const RenderBlock* cb = toRenderBlock(curr); - region = cb->clampToStartAndEndRegions(region); - RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region); - if (boxInfo) { - if (curr != containerBlock) - staticPosition -= cb->logicalWidth() - (boxInfo->logicalLeft() + boxInfo->logicalWidth()); - if (curr == enclosingBox) - staticPosition += enclosingBox->logicalWidth() - boxInfo->logicalWidth(); - } - } } else if (curr->isInline()) { if (curr->isRelPositioned()) { if (!curr->style()->logicalLeft().isAuto()) @@ -3336,11 +3058,9 @@ static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRigh } } -void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& computedValues, RenderRegion* region) const +void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& computedValues) const { if (isReplaced()) { - // FIXME: Positioned replaced elements inside a flow thread are not working properly - // with variable width regions (see https://bugs.webkit.org/show_bug.cgi?id=69896 ). computePositionedLogicalWidthReplaced(computedValues); return; } @@ -3365,7 +3085,7 @@ void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& compu // relative positioned inline. const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container()); - const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, region); + const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock); // Use the container block's direction except when calculating the static distance // This conforms with the reference results for abspos-replaced-width-margin-000.htm @@ -3406,7 +3126,7 @@ void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& compu // see FIXME 1 // Calculate the static distance if needed. - computeInlineStaticDistance(logicalLeftLength, logicalRightLength, this, containerBlock, containerLogicalWidth, region); + computeInlineStaticDistance(logicalLeftLength, logicalRightLength, this, containerBlock, containerLogicalWidth); // Calculate constraint equation values for 'width' case. computePositionedLogicalWidthUsing(style()->logicalWidth(), containerBlock, containerDirection, @@ -3449,25 +3169,6 @@ void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& compu } computedValues.m_extent += bordersPlusPadding; - - // Adjust logicalLeft if we need to for the flipped version of our writing mode in regions. - // FIXME: Add support for other types of objects as containerBlock, not only RenderBlock. - RenderFlowThread* flowThread = flowThreadContainingBlock(); - if (flowThread && !region && isWritingModeRoot() && isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode() && containerBlock->isRenderBlock()) { - ASSERT(containerBlock->canHaveBoxInfoInRegion()); - LayoutUnit logicalLeftPos = computedValues.m_position; - const RenderBlock* cb = toRenderBlock(containerBlock); - LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage(); - RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset); - if (cbRegion) { - cbRegion = cb->clampToStartAndEndRegions(cbRegion); - RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion); - if (boxInfo) { - logicalLeftPos += boxInfo->logicalLeft(); - computedValues.m_position = logicalLeftPos; - } - } - } } static void computeLogicalLeftPositionedOffset(LayoutUnit& logicalLeftPos, const RenderBox* child, LayoutUnit logicalWidthValue, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalWidth) @@ -3477,8 +3178,9 @@ static void computeLogicalLeftPositionedOffset(LayoutUnit& logicalLeftPos, const if (containerBlock->isHorizontalWritingMode() != child->isHorizontalWritingMode() && containerBlock->style()->isFlippedBlocksWritingMode()) { logicalLeftPos = containerLogicalWidth - logicalWidthValue - logicalLeftPos; logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderRight() : containerBlock->borderBottom()); - } else + } else { logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderLeft() : containerBlock->borderTop()); + } } void RenderBox::shrinkToFitWidth(const LayoutUnit availableSpace, const LayoutUnit logicalLeftValue, const LayoutUnit bordersPlusPadding, LogicalExtentComputedValues& computedValues) const @@ -3492,8 +3194,8 @@ void RenderBox::shrinkToFitWidth(const LayoutUnit availableSpace, const LayoutUn void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection, LayoutUnit containerLogicalWidth, LayoutUnit bordersPlusPadding, - Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight, - LogicalExtentComputedValues& computedValues) const + const Length& logicalLeft, const Length& logicalRight, const Length& marginLogicalLeft, + const Length& marginLogicalRight, LogicalExtentComputedValues& computedValues) const { if (logicalWidth.isIntrinsic()) logicalWidth = Length(computeIntrinsicLogicalWidthUsing(logicalWidth, containerLogicalWidth, bordersPlusPadding) - bordersPlusPadding, Fixed); @@ -3504,12 +3206,11 @@ void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const Re LayoutUnit logicalLeftValue = 0; - const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false); + const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, false); bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto(); bool logicalLeftIsAuto = logicalLeft.isAuto(); bool logicalRightIsAuto = logicalRight.isAuto(); - RenderView* renderView = view(); LayoutUnit& marginLogicalLeftValue = style()->isLeftToRightDirection() ? computedValues.m_margins.m_start : computedValues.m_margins.m_end; LayoutUnit& marginLogicalRightValue = style()->isLeftToRightDirection() ? computedValues.m_margins.m_end : computedValues.m_margins.m_start; if (!logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) { @@ -3528,10 +3229,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 = valueForLength(logicalLeft, containerLogicalWidth, renderView); - computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth, renderView)); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); + computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth)); - const LayoutUnit availableSpace = containerLogicalWidth - (logicalLeftValue + computedValues.m_extent + valueForLength(logicalRight, containerLogicalWidth, renderView) + bordersPlusPadding); + const LayoutUnit availableSpace = containerLogicalWidth - (logicalLeftValue + computedValues.m_extent + valueForLength(logicalRight, containerLogicalWidth) + bordersPlusPadding); // Margins are now the only unknown if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) { @@ -3552,16 +3253,16 @@ void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const Re } } else if (marginLogicalLeft.isAuto()) { // Solve for left margin - marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView); + marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth); marginLogicalLeftValue = availableSpace - marginLogicalRightValue; } else if (marginLogicalRight.isAuto()) { // Solve for right margin - marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView); + marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth); marginLogicalRightValue = availableSpace - marginLogicalLeftValue; } else { // Over-constrained, solve for left if direction is RTL - marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView); - marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView); + marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth); + marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth); // Use the containing block's direction rather than the parent block's // per CSS 2.1 reference test abspos-non-replaced-width-margin-000. @@ -3611,8 +3312,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 = minimumValueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView); - marginLogicalRightValue = minimumValueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView); + marginLogicalLeftValue = minimumValueForLength(marginLogicalLeft, containerRelativeLogicalWidth); + marginLogicalRightValue = minimumValueForLength(marginLogicalRight, containerRelativeLogicalWidth); const LayoutUnit availableSpace = containerLogicalWidth - (marginLogicalLeftValue + marginLogicalRightValue + bordersPlusPadding); @@ -3620,7 +3321,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 = valueForLength(logicalRight, containerLogicalWidth, renderView); + LayoutUnit logicalRightValue = valueForLength(logicalRight, containerLogicalWidth); // FIXME: would it be better to have shrink-to-fit in one step? LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding; @@ -3630,24 +3331,24 @@ void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const Re logicalLeftValue = availableSpace - (computedValues.m_extent + logicalRightValue); } else if (!logicalLeftIsAuto && logicalWidthIsAuto && logicalRightIsAuto) { // RULE 3: (use shrink-to-fit for width, and no need solve of right) - logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); shrinkToFitWidth(availableSpace, logicalLeftValue, bordersPlusPadding, computedValues); } else if (logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) { // RULE 4: (solve for left) - computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth, renderView)); - logicalLeftValue = availableSpace - (computedValues.m_extent + valueForLength(logicalRight, containerLogicalWidth, renderView)); + computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth)); + logicalLeftValue = availableSpace - (computedValues.m_extent + valueForLength(logicalRight, containerLogicalWidth)); } else if (!logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) { // RULE 5: (solve for width) - logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); if (autoWidthShouldFitContent()) shrinkToFitWidth(availableSpace, logicalLeftValue, bordersPlusPadding, computedValues); else - computedValues.m_extent = availableSpace - (logicalLeftValue + valueForLength(logicalRight, containerLogicalWidth, renderView)); + computedValues.m_extent = availableSpace - (logicalLeftValue + valueForLength(logicalRight, containerLogicalWidth)); } else if (!logicalLeftIsAuto && !logicalWidthIsAuto && logicalRightIsAuto) { // RULE 6: (no need solve for right) - logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); - computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth, renderView)); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); + computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth)); } } @@ -3779,25 +3480,6 @@ void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& comp // Set final height value. computedValues.m_extent += bordersPlusPadding; - - // Adjust logicalTop if we need to for perpendicular writing modes in regions. - // FIXME: Add support for other types of objects as containerBlock, not only RenderBlock. - RenderFlowThread* flowThread = flowThreadContainingBlock(); - if (flowThread && isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode() && containerBlock->isRenderBlock()) { - ASSERT(containerBlock->canHaveBoxInfoInRegion()); - LayoutUnit logicalTopPos = computedValues.m_position; - const RenderBlock* cb = toRenderBlock(containerBlock); - LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage() - logicalLeft(); - RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset); - if (cbRegion) { - cbRegion = cb->clampToStartAndEndRegions(cbRegion); - RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion); - if (boxInfo) { - logicalTopPos += boxInfo->logicalLeft(); - computedValues.m_position = logicalTopPos; - } - } - } } static void computeLogicalTopPositionedOffset(LayoutUnit& logicalTopPos, const RenderBox* child, LayoutUnit logicalHeightValue, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalHeight) @@ -3824,8 +3506,8 @@ static void computeLogicalTopPositionedOffset(LayoutUnit& logicalTopPos, const R void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalHeight, LayoutUnit bordersPlusPadding, LayoutUnit logicalHeight, - Length logicalTop, Length logicalBottom, Length marginBefore, Length marginAfter, - LogicalExtentComputedValues& computedValues) const + const Length& logicalTop, const Length& logicalBottom, const Length& marginBefore, + const Length& marginAfter, LogicalExtentComputedValues& computedValues) const { // 'top' and 'bottom' cannot both be 'auto' because 'top would of been // converted to the static position in computePositionedLogicalHeight() @@ -3834,14 +3516,13 @@ void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, LayoutUnit logicalHeightValue; LayoutUnit contentLogicalHeight = logicalHeight - bordersPlusPadding; - const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false); + const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, false); LayoutUnit logicalTopValue = 0; bool logicalHeightIsAuto = logicalHeightLength.isAuto(); bool logicalTopIsAuto = logicalTop.isAuto(); bool logicalBottomIsAuto = logicalBottom.isAuto(); - RenderView* renderView = view(); LayoutUnit resolvedLogicalHeight; // Height is never unsolved for tables. @@ -3852,7 +3533,7 @@ void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, if (logicalHeightLength.isIntrinsic()) resolvedLogicalHeight = computeIntrinsicLogicalContentHeightUsing(logicalHeightLength, contentLogicalHeight, bordersPlusPadding); else - resolvedLogicalHeight = adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeightLength, containerLogicalHeight, renderView)); + resolvedLogicalHeight = adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeightLength, containerLogicalHeight)); } if (!logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) { @@ -3868,9 +3549,9 @@ void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, // case because the value is not used for any further calculations. logicalHeightValue = resolvedLogicalHeight; - logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight); - const LayoutUnit availableSpace = containerLogicalHeight - (logicalTopValue + logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight, renderView) + bordersPlusPadding); + const LayoutUnit availableSpace = containerLogicalHeight - (logicalTopValue + logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight) + bordersPlusPadding); // Margins are now the only unknown if (marginBefore.isAuto() && marginAfter.isAuto()) { @@ -3880,16 +3561,16 @@ void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before; // account for odd valued differences } else if (marginBefore.isAuto()) { // Solve for top margin - computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView); + computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth); computedValues.m_margins.m_before = availableSpace - computedValues.m_margins.m_after; } else if (marginAfter.isAuto()) { // Solve for bottom margin - computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView); + computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth); computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before; } else { // Over-constrained, (no need solve for bottom) - computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView); - computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView); + computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth); + computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth); } } else { /*--------------------------------------------------------------------*\ @@ -3918,8 +3599,8 @@ void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, // because the value is not used for any further calculations. // Calculate margins, 'auto' margins are ignored. - computedValues.m_margins.m_before = minimumValueForLength(marginBefore, containerRelativeLogicalWidth, renderView); - computedValues.m_margins.m_after = minimumValueForLength(marginAfter, containerRelativeLogicalWidth, renderView); + computedValues.m_margins.m_before = minimumValueForLength(marginBefore, containerRelativeLogicalWidth); + computedValues.m_margins.m_after = minimumValueForLength(marginAfter, containerRelativeLogicalWidth); const LayoutUnit availableSpace = containerLogicalHeight - (computedValues.m_margins.m_before + computedValues.m_margins.m_after + bordersPlusPadding); @@ -3927,23 +3608,23 @@ void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, if (logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) { // RULE 1: (height is content based, solve of top) logicalHeightValue = contentLogicalHeight; - logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight, renderView)); + logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight)); } else if (!logicalTopIsAuto && logicalHeightIsAuto && logicalBottomIsAuto) { // RULE 3: (height is content based, no need solve of bottom) - logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight); logicalHeightValue = contentLogicalHeight; } else if (logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) { // RULE 4: (solve of top) logicalHeightValue = resolvedLogicalHeight; - logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight, renderView)); + logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight)); } else if (!logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) { // RULE 5: (solve of height) - logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); - logicalHeightValue = max<LayoutUnit>(0, availableSpace - (logicalTopValue + valueForLength(logicalBottom, containerLogicalHeight, renderView))); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight); + logicalHeightValue = max<LayoutUnit>(0, availableSpace - (logicalTopValue + valueForLength(logicalBottom, containerLogicalHeight))); } else if (!logicalTopIsAuto && !logicalHeightIsAuto && logicalBottomIsAuto) { // RULE 6: (no need solve of bottom) logicalHeightValue = resolvedLogicalHeight; - logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight); } } computedValues.m_extent = logicalHeightValue; @@ -3966,7 +3647,7 @@ void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValue const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container()); const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock); - const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false); + const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, false); // To match WinIE, in quirks mode use the parent's 'direction' property // instead of the the container block's. @@ -3998,7 +3679,7 @@ void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValue * else if 'direction' is 'rtl', set 'right' to the static position. \*-----------------------------------------------------------------------*/ // see FIXME 1 - computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth, 0); // FIXME: Pass the region. + computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth); /*-----------------------------------------------------------------------*\ * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left' @@ -4021,14 +3702,13 @@ void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValue \*-----------------------------------------------------------------------*/ 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 = valueForLength(logicalLeft, containerLogicalWidth, renderView); - logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); + logicalRightValue = valueForLength(logicalRight, containerLogicalWidth); LayoutUnit difference = availableSpace - (logicalLeftValue + logicalRightValue); if (difference > 0) { @@ -4051,39 +3731,39 @@ void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValue * that value. \*-----------------------------------------------------------------------*/ } else if (logicalLeft.isAuto()) { - marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView); - marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView); - logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView); + marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth); + marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth); + logicalRightValue = valueForLength(logicalRight, containerLogicalWidth); // Solve for 'left' logicalLeftValue = availableSpace - (logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias); } else if (logicalRight.isAuto()) { - marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView); - marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView); - logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); + marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth); + marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); // Solve for 'right' logicalRightValue = availableSpace - (logicalLeftValue + marginLogicalLeftAlias + marginLogicalRightAlias); } else if (marginLogicalLeft.isAuto()) { - marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView); - logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); - logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView); + marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); + logicalRightValue = valueForLength(logicalRight, containerLogicalWidth); // Solve for 'margin-left' marginLogicalLeftAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalRightAlias); } else if (marginLogicalRight.isAuto()) { - marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView); - logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); - logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView); + marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); + logicalRightValue = valueForLength(logicalRight, containerLogicalWidth); // Solve for 'margin-right' marginLogicalRightAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalLeftAlias); } else { // Nothing is 'auto', just calculate the values. - marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView); - marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView); - logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView); - logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); + marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth); + marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth); + logicalRightValue = valueForLength(logicalRight, containerLogicalWidth); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); // 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 = computedValues.m_extent + logicalLeftValue + logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias; @@ -4135,7 +3815,7 @@ void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValu const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container()); const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock); - const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false); + const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, false); // Variables to solve. Length marginBefore = style()->marginBefore(); @@ -4145,7 +3825,6 @@ void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValu Length logicalTop = style()->logicalTop(); Length logicalBottom = style()->logicalBottom(); - RenderView* renderView = view(); /*-----------------------------------------------------------------------*\ * 1. The used value of 'height' is determined as for inline replaced @@ -4189,8 +3868,8 @@ void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValu // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined. ASSERT(!(logicalTop.isAuto() || logicalBottom.isAuto())); - logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); - logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight); + logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight); LayoutUnit difference = availableSpace - (logicalTopValue + logicalBottomValue); // NOTE: This may result in negative values. @@ -4202,39 +3881,39 @@ void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValu * for that value. \*-----------------------------------------------------------------------*/ } else if (logicalTop.isAuto()) { - marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView); - marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView); - logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView); + marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth); + marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth); + logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight); // Solve for 'top' logicalTopValue = availableSpace - (logicalBottomValue + marginBeforeAlias + marginAfterAlias); } else if (logicalBottom.isAuto()) { - marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView); - marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView); - logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); + marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth); + marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight); // 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 = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView); - logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); - logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView); + marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight); + logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight); // Solve for 'margin-top' marginBeforeAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginAfterAlias); } else if (marginAfter.isAuto()) { - marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView); - logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); - logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView); + marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight); + logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight); // Solve for 'margin-bottom' marginAfterAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginBeforeAlias); } else { // Nothing is 'auto', just calculate the values. - marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView); - marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView); - logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); + marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth); + marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight); // NOTE: It is not necessary to solve for 'bottom' because we don't ever // use the value. } @@ -4267,10 +3946,10 @@ LayoutRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, LayoutUnit rect.move(LayoutSize(width() - caretWidth, 0)); if (box) { - RootInlineBox* rootBox = box->root(); - LayoutUnit top = rootBox->lineTop(); + RootInlineBox& rootBox = box->root(); + LayoutUnit top = rootBox.lineTop(); rect.setY(top); - rect.setHeight(rootBox->lineBottom() - top); + rect.setHeight(rootBox.lineBottom() - top); } // If height of box is smaller than font height, use the latter one, @@ -4308,7 +3987,8 @@ LayoutRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, LayoutUnit PositionWithAffinity RenderBox::positionForPoint(const LayoutPoint& point) { // no children...return this render object's element, if there is one, and offset 0 - if (!firstChild()) + RenderObject* firstChild = slowFirstChild(); + if (!firstChild) return createPositionWithAffinity(nonPseudoNode() ? firstPositionInOrBeforeNode(nonPseudoNode()) : Position()); if (isTable() && nonPseudoNode()) { @@ -4329,8 +4009,8 @@ PositionWithAffinity RenderBox::positionForPoint(const LayoutPoint& point) if (isTableRow()) adjustedPoint.moveBy(location()); - for (RenderObject* renderObject = firstChild(); renderObject; renderObject = renderObject->nextSibling()) { - if ((!renderObject->firstChild() && !renderObject->isInline() && !renderObject->isRenderBlockFlow() ) + for (RenderObject* renderObject = firstChild; renderObject; renderObject = renderObject->nextSibling()) { + if ((!renderObject->slowFirstChild() && !renderObject->isInline() && !renderObject->isRenderBlockFlow() ) || renderObject->style()->visibility() != VISIBLE) continue; @@ -4403,9 +4083,18 @@ bool RenderBox::avoidsFloats() const return isReplaced() || hasOverflowClip() || isHR() || isLegend() || isWritingModeRoot() || isFlexItemIncludingDeprecated(); } +void RenderBox::markForPaginationRelayoutIfNeeded(SubtreeLayoutScope& layoutScope) +{ + ASSERT(!needsLayout()); + // If fragmentation height has changed, we need to lay out. No need to enter the renderer if it + // is childless, though. + if (view()->layoutState()->pageLogicalHeightChanged() && slowFirstChild()) + layoutScope.setChildNeedsLayout(this); +} + void RenderBox::addVisualEffectOverflow() { - if (!style()->boxShadow() && !style()->hasBorderImageOutsets()) + if (!style()->boxShadow() && !style()->hasBorderImageOutsets() && !style()->hasOutline()) return; bool isFlipped = style()->isFlippedBlocksWritingMode(); @@ -4444,7 +4133,16 @@ void RenderBox::addVisualEffectOverflow() overflowMaxY = max(overflowMaxY, borderBox.maxY() + ((!isFlipped || !isHorizontal) ? borderOutsets.bottom() : borderOutsets.top())); } - // Add in the final overflow with shadows and outsets combined. + if (style()->hasOutline()) { + LayoutUnit outlineSize = style()->outlineSize(); + + overflowMinX = min(overflowMinX, borderBox.x() - outlineSize); + overflowMaxX = max(overflowMaxX, borderBox.maxX() + outlineSize); + overflowMinY = min(overflowMinY, borderBox.y() - outlineSize); + overflowMaxY = max(overflowMaxY, borderBox.maxY() + outlineSize); + } + + // Add in the final overflow with shadows, outsets and outline combined. LayoutRect visualEffectOverflow(overflowMinX, overflowMinY, overflowMaxX - overflowMinX, overflowMaxY - overflowMinY); addVisualOverflow(visualEffectOverflow); } @@ -4494,13 +4192,6 @@ void RenderBox::addLayoutOverflow(const LayoutRect& rect) hasTopOverflow = true; } - if (hasColumns() && style()->columnProgression() == ReverseColumnProgression) { - if (isHorizontalWritingMode() ^ !style()->hasInlineColumnAxis()) - hasLeftOverflow = !hasLeftOverflow; - else - hasTopOverflow = !hasTopOverflow; - } - if (!hasTopOverflow) overflowRect.shiftYEdgeTo(max(overflowRect.y(), clientBox.y())); else @@ -4542,7 +4233,7 @@ void RenderBox::addContentsVisualOverflow(const LayoutRect& rect) } if (!m_overflow) - m_overflow = adoptPtr(new RenderOverflow(clientBoxRect(), borderBoxRect())); + m_overflow = adoptPtr(new RenderOverflow(noOverflowRect(), borderBoxRect())); m_overflow->addContentsVisualOverflow(rect); } @@ -4599,7 +4290,7 @@ bool RenderBox::percentageLogicalHeightIsResolvableFromBlock(const RenderBlock* return percentageLogicalHeightIsResolvableFromBlock(cb->containingBlock(), cb->isOutOfFlowPositioned()); if (cb->isRenderView() || inQuirksMode || isOutOfFlowPositionedWithSpecifiedHeight) return true; - if (cb->isRoot() && isOutOfFlowPositioned) { + if (cb->isDocumentElement() && isOutOfFlowPositioned) { // Match the positioned objects behavior, which is that positioned objects will fill their viewport // always. Note we could only hit this case by recurring into computePercentageLogicalHeight on a positioned containing block. return true; @@ -4742,14 +4433,16 @@ LayoutRect RenderBox::layoutOverflowRectForPropagation(RenderStyle* parentStyle) LayoutRect RenderBox::noOverflowRect() const { - // Because of the special coodinate system used for overflow rectangles and many other + // Because of the special coordinate system used for overflow rectangles and many other // rectangles (not quite logical, not quite physical), we need to flip the block progression // coordinate in vertical-rl and horizontal-bt writing modes. In other words, the rectangle // returned is physical, except for the block direction progression coordinate (y in horizontal // writing modes, x in vertical writing modes), which is always "logical top". Apart from the // flipping, this method does the same as clientBoxRect(). - LayoutUnit left = borderLeft() + (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? verticalScrollbarWidth() : 0); + const int scrollBarWidth = verticalScrollbarWidth(); + const int scrollBarHeight = horizontalScrollbarHeight(); + LayoutUnit left = borderLeft() + (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? scrollBarWidth : 0); LayoutUnit top = borderTop(); LayoutUnit right = borderRight(); LayoutUnit bottom = borderBottom(); @@ -4765,9 +4458,9 @@ LayoutRect RenderBox::noOverflowRect() const // clientBoxRect() or paddingBoxRect() in this method, rather than fiddling with the edges on // our own. if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) - rect.contract(0, horizontalScrollbarHeight()); + rect.contract(0, scrollBarHeight); else - rect.contract(verticalScrollbarWidth(), horizontalScrollbarHeight()); + rect.contract(scrollBarWidth, scrollBarHeight); return rect; } @@ -4880,22 +4573,11 @@ LayoutSize RenderBox::topLeftLocationOffset() const return LayoutSize(rect.x(), rect.y()); } -bool RenderBox::hasRelativeDimensions() const -{ - // FIXME: This should probably include viewport percentage heights as well. - return style()->height().isPercent() || style()->width().isPercent() - || style()->maxHeight().isPercent() || style()->maxWidth().isPercent() - || style()->minHeight().isPercent() || style()->minWidth().isPercent(); -} - bool RenderBox::hasRelativeLogicalHeight() const { return style()->logicalHeight().isPercent() || style()->logicalMinHeight().isPercent() - || style()->logicalMaxHeight().isPercent() - || style()->logicalHeight().isViewportPercentage() - || style()->logicalMinHeight().isViewportPercentage() - || style()->logicalMaxHeight().isViewportPercentage(); + || style()->logicalMaxHeight().isPercent(); } static void markBoxForRelayoutAfterSplit(RenderBox* box) @@ -4909,7 +4591,7 @@ static void markBoxForRelayoutAfterSplit(RenderBox* box) } else if (box->isTableSection()) toRenderTableSection(box)->setNeedsCellRecalc(); - box->setNeedsLayoutAndPrefWidthsRecalc(); + box->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } RenderObject* RenderBox::splitAnonymousBoxesAroundChild(RenderObject* beforeChild) @@ -4918,7 +4600,7 @@ RenderObject* RenderBox::splitAnonymousBoxesAroundChild(RenderObject* beforeChil while (beforeChild->parent() != this) { RenderBox* boxToSplit = toRenderBox(beforeChild->parent()); - if (boxToSplit->firstChild() != beforeChild && boxToSplit->isAnonymous()) { + if (boxToSplit->slowFirstChild() != beforeChild && boxToSplit->isAnonymous()) { didSplitParentAnonymousBoxes = true; // We have to split the parent box into two boxes and move children @@ -4928,7 +4610,7 @@ RenderObject* RenderBox::splitAnonymousBoxesAroundChild(RenderObject* beforeChil RenderBox* parentBox = toRenderBox(boxToSplit->parent()); // We need to invalidate the |parentBox| before inserting the new node // so that the table repainting logic knows the structure is dirty. - // See for example RenderTableCell:clippedOverflowRectForRepaint. + // See for example RenderTableCell:clippedOverflowRectForPaintInvalidation. markBoxForRelayoutAfterSplit(parentBox); parentBox->virtualChildren()->insertChildNode(parentBox, postBox, boxToSplit->nextSibling()); boxToSplit->moveChildrenTo(postBox, beforeChild, 0, true); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderBox.h b/chromium/third_party/WebKit/Source/core/rendering/RenderBox.h index 350b640d75c..c9d967df7a5 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderBox.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderBox.h @@ -23,6 +23,7 @@ #ifndef RenderBox_h #define RenderBox_h +#include "core/animation/ActiveAnimations.h" #include "core/rendering/RenderBoxModelObject.h" #include "core/rendering/RenderOverflow.h" #include "core/rendering/shapes/ShapeOutsideInfo.h" @@ -30,13 +31,12 @@ namespace WebCore { -class RenderBoxRegionInfo; -class RenderRegion; struct PaintInfo; enum SizeType { MainOrPreferredSize, MinSize, MaxSize }; enum AvailableLogicalHeightType { ExcludeMarginBorderPadding, IncludeMarginBorderPadding }; enum OverlayScrollbarSizeRelevancy { IgnoreOverlayScrollbarSize, IncludeOverlayScrollbarSize }; +enum MarginDirection { BlockDirection, InlineDirection }; enum ShouldComputePreferred { ComputeActual, ComputePreferred }; @@ -47,14 +47,39 @@ enum ScrollOffsetClamping { ScrollOffsetClamped }; +struct RenderBoxRareData { + WTF_MAKE_NONCOPYABLE(RenderBoxRareData); WTF_MAKE_FAST_ALLOCATED; +public: + RenderBoxRareData() + : m_inlineBoxWrapper(0) + , m_overrideLogicalContentHeight(-1) + , m_overrideLogicalContentWidth(-1) + { + } + + // For inline replaced elements, the inline box that owns us. + InlineBox* m_inlineBoxWrapper; + + LayoutUnit m_overrideLogicalContentHeight; + LayoutUnit m_overrideLogicalContentWidth; +}; + + class RenderBox : public RenderBoxModelObject { public: explicit RenderBox(ContainerNode*); - virtual ~RenderBox(); // hasAutoZIndex only returns true if the element is positioned or a flex-item since // position:static elements that are not flex-items get their z-index coerced to auto. - virtual bool requiresLayer() const OVERRIDE { return isRoot() || isPositioned() || createsGroup() || hasClipPath() || hasOverflowClip() || hasTransform() || hasHiddenBackface() || hasReflection() || style()->specifiesColumns() || !style()->hasAutoZIndex(); } + virtual LayerType layerTypeRequired() const OVERRIDE + { + if (isPositioned() || createsGroup() || hasClipPath() || hasTransform() || hasHiddenBackface() || hasReflection() || style()->specifiesColumns() || !style()->hasAutoZIndex() || style()->shouldCompositeForCurrentAnimations()) + return NormalLayer; + if (hasOverflowClip()) + return OverflowClipLayer; + + return NoLayer; + } virtual bool backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const OVERRIDE; @@ -87,7 +112,7 @@ public: LayoutUnit logicalWidth() const { return style()->isHorizontalWritingMode() ? width() : height(); } LayoutUnit logicalHeight() const { return style()->isHorizontalWritingMode() ? height() : width(); } - LayoutUnit constrainLogicalWidthInRegionByMinMax(LayoutUnit, LayoutUnit, RenderBlock*, RenderRegion* = 0) const; + LayoutUnit constrainLogicalWidthByMinMax(LayoutUnit, LayoutUnit, RenderBlock*) const; LayoutUnit constrainLogicalHeightByMinMax(LayoutUnit logicalHeight, LayoutUnit intrinsicContentHeight) const; LayoutUnit constrainContentBoxLogicalHeightByMinMax(LayoutUnit logicalHeight, LayoutUnit intrinsicContentHeight) const; @@ -167,8 +192,6 @@ public: // 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(const RenderLayerModelObject* /*repaintContainer*/, const RenderGeometryMap*) const OVERRIDE FINAL; virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) OVERRIDE; // Use this with caution! No type checking is done! @@ -207,8 +230,9 @@ public: void addOverflowFromChild(RenderBox* child) { addOverflowFromChild(child, child->locationOffset()); } void addOverflowFromChild(RenderBox* child, const LayoutSize& delta); void clearLayoutOverflow(); + void clearAllOverflows() { m_overflow.clear(); } - void updateLayerTransform(); + void updateLayerTransformAfterLayout(); LayoutUnit contentWidth() const { return clientWidth() - paddingLeft() - paddingRight(); } LayoutUnit contentHeight() const { return clientHeight() - paddingTop() - paddingBottom(); } @@ -217,18 +241,15 @@ public: // 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). - virtual LayoutUnit offsetWidth() const { return width(); } - virtual LayoutUnit offsetHeight() const { return height(); } + virtual LayoutUnit offsetWidth() const OVERRIDE { return width(); } + virtual LayoutUnit offsetHeight() const OVERRIDE { return height(); } virtual int pixelSnappedOffsetWidth() const OVERRIDE FINAL; virtual int pixelSnappedOffsetHeight() const OVERRIDE FINAL; - bool canDetermineWidthWithoutLayout() const; - LayoutUnit fixedOffsetWidth() const; - // More IE extensions. clientWidth and clientHeight represent the interior of an object // excluding border and scrollbar. clientLeft/Top are just the borderLeftWidth and borderTopWidth. - LayoutUnit clientLeft() const { return borderLeft(); } + LayoutUnit clientLeft() const { return borderLeft() + (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? verticalScrollbarWidth() : 0); } LayoutUnit clientTop() const { return borderTop(); } LayoutUnit clientWidth() const; LayoutUnit clientHeight() const; @@ -245,12 +266,14 @@ public: // scrollLeft/Top return the current scroll position. These methods are virtual so that objects like // textareas can scroll shadow content (but pretend that they are the objects that are // scrolling). - virtual int scrollLeft() const; - virtual int scrollTop() const; - virtual int scrollWidth() const; - virtual int scrollHeight() const; - virtual void setScrollLeft(int); - virtual void setScrollTop(int); + virtual LayoutUnit scrollLeft() const; + virtual LayoutUnit scrollTop() const; + virtual LayoutUnit scrollWidth() const; + virtual LayoutUnit scrollHeight() const; + int pixelSnappedScrollWidth() const; + int pixelSnappedScrollHeight() const; + virtual void setScrollLeft(LayoutUnit); + virtual void setScrollTop(LayoutUnit); void scrollToOffset(const IntSize&); void scrollByRecursively(const IntSize& delta, ScrollOffsetClamping = ScrollOffsetUnclamped); @@ -304,20 +327,19 @@ public: virtual LayoutUnit collapsedMarginBefore() const { return marginBefore(); } virtual LayoutUnit collapsedMarginAfter() const { return marginAfter(); } - virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const; - virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; + virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const OVERRIDE; + virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const OVERRIDE; - LayoutRect reflectionBox() const; int reflectionOffset() const; // Given a rect in the object's coordinate space, returns the corresponding rect in the reflection. LayoutRect reflectedRect(const LayoutRect&) const; - virtual void layout(); - virtual void paint(PaintInfo&, const LayoutPoint&); + virtual void layout() OVERRIDE; + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; - virtual LayoutUnit minPreferredLogicalWidth() const; - virtual LayoutUnit maxPreferredLogicalWidth() const; + virtual LayoutUnit minPreferredLogicalWidth() const OVERRIDE; + virtual LayoutUnit maxPreferredLogicalWidth() const OVERRIDE; // FIXME: We should rename these back to overrideLogicalHeight/Width and have them store // the border-box height/width like the regular height/width accessors on RenderBox. @@ -342,7 +364,7 @@ public: void clearContainingBlockOverrideSize(); void clearOverrideContainingBlockContentLogicalHeight(); - virtual LayoutSize offsetFromContainer(RenderObject*, const LayoutPoint&, bool* offsetDependsOnPoint = 0) const; + virtual LayoutSize offsetFromContainer(const RenderObject*, const LayoutPoint&, bool* offsetDependsOnPoint = 0) const OVERRIDE; LayoutUnit adjustBorderBoxLogicalWidthForBoxSizing(LayoutUnit width) const; LayoutUnit adjustBorderBoxLogicalHeightForBoxSizing(LayoutUnit height) const; @@ -364,17 +386,13 @@ public: LayoutUnit m_position; ComputedMarginValues m_margins; }; - // Resolve auto margins in the inline direction of the containing block so that objects can be pushed to the start, middle or end + // Resolve auto margins in the chosen direction of the containing block so that objects can be pushed to the start, middle or end // of the containing block. - void computeInlineDirectionMargins(RenderBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const; + void computeMarginsForDirection(MarginDirection forDirection, const RenderBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd, Length marginStartLength, Length marginStartEnd) const; // Used to resolve margins in the containing block's block-flow direction. - void computeBlockDirectionMargins(const RenderBlock* containingBlock, LayoutUnit& marginBefore, LayoutUnit& marginAfter) const; void computeAndSetBlockDirectionMargins(const RenderBlock* containingBlock); - enum RenderBoxRegionInfoFlags { CacheRenderBoxRegionInfo, DoNotCacheRenderBoxRegionInfo }; - LayoutRect borderBoxRectInRegion(RenderRegion*, RenderBoxRegionInfoFlags = CacheRenderBoxRegionInfo) const; - void clearRenderBoxRegionInfo(); virtual LayoutUnit offsetFromLogicalTopOfFirstPage() const; void positionLineBox(InlineBox*); @@ -385,51 +403,50 @@ public: // For inline replaced elements, this function returns the inline box that owns us. Enables // the replaced RenderObject to quickly determine what line it is contained on and to easily // iterate over structures on the line. - InlineBox* inlineBoxWrapper() const { return m_inlineBoxWrapper; } + InlineBox* inlineBoxWrapper() const { return m_rareData ? m_rareData->m_inlineBoxWrapper : 0; } void setInlineBoxWrapper(InlineBox*); void deleteLineBoxWrapper(); - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE; - virtual void computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect&, bool fixed = false) const OVERRIDE; + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const OVERRIDE; + virtual void mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect&, bool fixed = false) const OVERRIDE; void repaintDuringLayoutIfMoved(const LayoutRect&); virtual void repaintOverhangingFloats(bool paintAllDescendants); - virtual LayoutUnit containingBlockLogicalWidthForContent() const; + virtual LayoutUnit containingBlockLogicalWidthForContent() const OVERRIDE; LayoutUnit containingBlockLogicalHeightForContent(AvailableLogicalHeightType) const; - LayoutUnit containingBlockLogicalWidthForContentInRegion(RenderRegion*) const; - LayoutUnit containingBlockAvailableLineWidthInRegion(RenderRegion*) const; + LayoutUnit containingBlockAvailableLineWidth() const; LayoutUnit perpendicularContainingBlockLogicalHeight() const; virtual void updateLogicalWidth(); virtual void updateLogicalHeight(); virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const; - RenderBoxRegionInfo* renderBoxRegionInfo(RenderRegion*, RenderBoxRegionInfoFlags = CacheRenderBoxRegionInfo) const; - void computeLogicalWidthInRegion(LogicalExtentComputedValues&, RenderRegion* = 0) const; + void computeLogicalWidth(LogicalExtentComputedValues&) const; bool stretchesToViewport() const { - return document().inQuirksMode() && style()->logicalHeight().isAuto() && !isFloatingOrOutOfFlowPositioned() && (isRoot() || isBody()) && !document().shouldDisplaySeamlesslyWithParent() && !isInline(); + return document().inQuirksMode() && style()->logicalHeight().isAuto() && !isFloatingOrOutOfFlowPositioned() && (isDocumentElement() || isBody()) && !isInline(); } virtual LayoutSize intrinsicSize() const { return LayoutSize(); } LayoutUnit intrinsicLogicalWidth() const { return style()->isHorizontalWritingMode() ? intrinsicSize().width() : intrinsicSize().height(); } LayoutUnit intrinsicLogicalHeight() const { return style()->isHorizontalWritingMode() ? intrinsicSize().height() : intrinsicSize().width(); } + virtual LayoutUnit intrinsicContentLogicalHeight() const { return m_intrinsicContentLogicalHeight; } // Whether or not the element shrinks to its intrinsic width (rather than filling the width // of a containing block). HTML4 buttons, <select>s, <input>s, legends, and floating/compact elements do this. - bool sizesLogicalWidthToFitContent(SizeType) const; + bool sizesLogicalWidthToFitContent(const Length& logicalWidth) const; - LayoutUnit shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlockFlow* cb, RenderRegion*) const; + LayoutUnit shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlockFlow* cb) const; - LayoutUnit computeLogicalWidthInRegionUsing(SizeType, Length logicalWidth, LayoutUnit availableLogicalWidth, const RenderBlock* containingBlock, RenderRegion*) const; + LayoutUnit computeLogicalWidthUsing(SizeType, const Length& logicalWidth, LayoutUnit availableLogicalWidth, const RenderBlock* containingBlock) const; LayoutUnit computeLogicalHeightUsing(const Length& height, LayoutUnit intrinsicContentHeight) const; LayoutUnit computeContentLogicalHeight(const Length& height, LayoutUnit intrinsicContentHeight) const; LayoutUnit computeContentAndScrollbarLogicalHeightUsing(const Length& height, LayoutUnit intrinsicContentHeight) const; - LayoutUnit computeReplacedLogicalWidthUsing(Length width) const; + LayoutUnit computeReplacedLogicalWidthUsing(const Length& width) const; LayoutUnit computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, ShouldComputePreferred = ComputeActual) const; - LayoutUnit computeReplacedLogicalHeightUsing(Length height) const; + LayoutUnit computeReplacedLogicalHeightUsing(const Length& height) const; LayoutUnit computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutUnit logicalHeight) const; virtual LayoutUnit computeReplacedLogicalWidth(ShouldComputePreferred = ComputeActual) const; @@ -452,7 +469,7 @@ public: int horizontalScrollbarHeight() const; int instrinsicScrollbarLogicalWidth() const; int scrollbarLogicalHeight() const { return style()->isHorizontalWritingMode() ? horizontalScrollbarHeight() : verticalScrollbarWidth(); } - virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1); + virtual bool scroll(ScrollDirection, ScrollGranularity, float delta = 1); bool canBeScrolledAndHasScrollableArea() const; virtual bool canBeProgramaticallyScrolled() const; virtual void autoscroll(const IntPoint&); @@ -467,8 +484,8 @@ public: bool hasAutoHorizontalScrollbar() const { return hasOverflowClip() && (style()->overflowX() == OAUTO || style()->overflowX() == OOVERLAY); } bool scrollsOverflow() const { return scrollsOverflowX() || scrollsOverflowY(); } - bool hasScrollableOverflowX() const { return scrollsOverflowX() && scrollWidth() != clientWidth(); } - bool hasScrollableOverflowY() const { return scrollsOverflowY() && scrollHeight() != clientHeight(); } + bool hasScrollableOverflowX() const { return scrollsOverflowX() && pixelSnappedScrollWidth() != pixelSnappedClientWidth(); } + bool hasScrollableOverflowY() const { return scrollsOverflowY() && pixelSnappedScrollHeight() != pixelSnappedClientHeight(); } virtual bool scrollsOverflowX() const { return hasOverflowClip() && (style()->overflowX() == OSCROLL || hasAutoHorizontalScrollbar()); } virtual bool scrollsOverflowY() const { return hasOverflowClip() && (style()->overflowY() == OSCROLL || hasAutoVerticalScrollbar()); } bool usesCompositedScrolling() const; @@ -480,10 +497,10 @@ public: bool hasUnsplittableScrollingOverflow() const; bool isUnsplittableForPagination() const; - virtual LayoutRect localCaretRect(InlineBox*, int caretOffset, LayoutUnit* extraWidthToEndOfLine = 0); + virtual LayoutRect localCaretRect(InlineBox*, int caretOffset, LayoutUnit* extraWidthToEndOfLine = 0) OVERRIDE; - virtual LayoutRect overflowClipRect(const LayoutPoint& location, RenderRegion*, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize); - LayoutRect clipRect(const LayoutPoint& location, RenderRegion*); + virtual LayoutRect overflowClipRect(const LayoutPoint& location, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize); + LayoutRect clipRect(const LayoutPoint& location); virtual bool hasControlClip() const { return false; } virtual LayoutRect controlClipRect(const LayoutPoint&) const { return LayoutRect(); } bool pushContentsClip(PaintInfo&, const LayoutPoint& accumulatedOffset, ContentsClipBehavior); @@ -493,7 +510,7 @@ public: virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&); virtual void paintMask(PaintInfo&, const LayoutPoint&); virtual void paintClippingMask(PaintInfo&, const LayoutPoint&); - virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) OVERRIDE; // Called when a positioned object moves but doesn't necessarily change size. A simplified layout is attempted // that just updates the object's position. If the size does change, the object remains dirty. @@ -508,8 +525,6 @@ public: return true; } - LayoutRect maskClipRect(); - virtual PositionWithAffinity positionForPoint(const LayoutPoint&) OVERRIDE; void removeFloatingOrPositionedChildFromBlockLists(); @@ -522,14 +537,14 @@ public: bool shrinkToAvoidFloats() const; virtual bool avoidsFloats() const; - virtual void markForPaginationRelayoutIfNeeded(SubtreeLayoutScope&) { } + virtual void markForPaginationRelayoutIfNeeded(SubtreeLayoutScope&); bool isWritingModeRoot() const { return !parent() || parent()->style()->writingMode() != style()->writingMode(); } bool isDeprecatedFlexItem() const { return !isInline() && !isFloatingOrOutOfFlowPositioned() && parent() && parent()->isDeprecatedFlexibleBox(); } bool isFlexItemIncludingDeprecated() const { return !isInline() && !isFloatingOrOutOfFlowPositioned() && parent() && parent()->isFlexibleBoxIncludingDeprecated(); } - virtual LayoutUnit lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const; + virtual LayoutUnit lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const OVERRIDE; virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const OVERRIDE; virtual LayoutUnit offsetLeft() const OVERRIDE; @@ -557,13 +572,12 @@ public: bool hasVisualOverflow() const { return m_overflow && !borderBoxRect().contains(m_overflow->visualOverflowRect()); } virtual bool needsPreferredWidthsRecalculation() const; - virtual void computeIntrinsicRatioInformation(FloatSize& /* intrinsicSize */, double& /* intrinsicRatio */, bool& /* isPercentageIntrinsicSize */) const { } + virtual void computeIntrinsicRatioInformation(FloatSize& /* intrinsicSize */, double& /* intrinsicRatio */) const { } IntSize scrolledContentOffset() const; LayoutSize cachedSizeForOverflowClip() const; void applyCachedClipAndScrollOffsetForRepaint(LayoutRect& paintRect) const; - virtual bool hasRelativeDimensions() const; virtual bool hasRelativeLogicalHeight() const; bool hasHorizontalLayoutOverflow() const @@ -596,7 +610,7 @@ public: ShapeOutsideInfo* shapeOutsideInfo() const { - return ShapeOutsideInfo::isEnabledFor(this) ? ShapeOutsideInfo::info(this) : 0; + return ShapeOutsideInfo::isEnabledFor(*this) ? ShapeOutsideInfo::info(*this) : 0; } void markShapeOutsideDependentsForLayout() @@ -605,18 +619,21 @@ public: removeFloatingOrPositionedChildFromBlockLists(); } + virtual void invalidateTreeAfterLayout(const RenderLayerModelObject&) OVERRIDE; + protected: - virtual void willBeDestroyed(); + virtual void willBeDestroyed() OVERRIDE; - virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleWillChange(StyleDifference, const RenderStyle& newStyle) OVERRIDE; + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; virtual void updateFromStyle() OVERRIDE; - LayoutRect backgroundPaintedExtent() const; + // Returns false if it could not cheaply compute the extent (e.g. fixed background), in which case the returned rect may be incorrect. + bool getBackgroundPaintedExtent(LayoutRect&) const; virtual bool foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const; virtual bool computeBackgroundIsKnownToBeObscured() OVERRIDE; - virtual void paintBackgroundWithBorderAndBoxShadow(PaintInfo&, const LayoutRect&, BackgroundBleedAvoidance); + void paintBackgroundWithBorderAndBoxShadow(PaintInfo&, const LayoutRect&, BackgroundBleedAvoidance); void paintBackground(const PaintInfo&, const LayoutRect&, BackgroundBleedAvoidance = BackgroundBleedNone); void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, BackgroundBleedAvoidance, CompositeOperator, RenderObject* backgroundObject); @@ -628,15 +645,15 @@ protected: BackgroundBleedAvoidance determineBackgroundBleedAvoidance(GraphicsContext*) const; bool backgroundHasOpaqueTopLayer() const; - void computePositionedLogicalWidth(LogicalExtentComputedValues&, RenderRegion* = 0) const; + void computePositionedLogicalWidth(LogicalExtentComputedValues&) const; - LayoutUnit computeIntrinsicLogicalWidthUsing(Length logicalWidthLength, LayoutUnit availableLogicalWidth, LayoutUnit borderAndPadding) const; - LayoutUnit computeIntrinsicLogicalContentHeightUsing(Length logicalHeightLength, LayoutUnit intrinsicContentHeight, LayoutUnit borderAndPadding) const; + LayoutUnit computeIntrinsicLogicalWidthUsing(const Length& logicalWidthLength, LayoutUnit availableLogicalWidth, LayoutUnit borderAndPadding) const; + LayoutUnit computeIntrinsicLogicalContentHeightUsing(const Length& logicalHeightLength, LayoutUnit intrinsicContentHeight, LayoutUnit borderAndPadding) const; virtual bool shouldComputeSizeAsReplaced() const { return isReplaced() && !isInlineBlockOrInlineTable(); } virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE; - virtual void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const; + virtual void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const OVERRIDE; void paintRootBoxFillLayers(const PaintInfo&); @@ -645,6 +662,8 @@ protected: virtual void addLayerHitTestRects(LayerHitTestRects&, const RenderLayer* currentCompositedLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const OVERRIDE; virtual void computeSelfHitTestRects(Vector<LayoutRect>&, const LayoutPoint& layerOffset) const OVERRIDE; + void updateIntrinsicContentLogicalHeight(LayoutUnit intrinsicContentLogicalHeight) const { m_intrinsicContentLogicalHeight = intrinsicContentLogicalHeight; } + private: void updateShapeOutsideInfoAfterStyleChange(const RenderStyle&, const RenderStyle* oldStyle); void updateGridPositionAfterStyleChange(const RenderStyle*); @@ -657,20 +676,18 @@ private: bool skipContainingBlockForPercentHeightCalculation(const RenderBox* containingBlock) const; - LayoutUnit containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, RenderRegion* = 0, bool checkForPerpendicularWritingMode = true) const; + LayoutUnit containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode = true) const; LayoutUnit containingBlockLogicalHeightForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode = true) const; - LayoutUnit viewLogicalHeightForPercentages() const; - void computePositionedLogicalHeight(LogicalExtentComputedValues&) const; void computePositionedLogicalWidthUsing(Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection, LayoutUnit containerLogicalWidth, LayoutUnit bordersPlusPadding, - Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight, - LogicalExtentComputedValues&) const; + const Length& logicalLeft, const Length& logicalRight, const Length& marginLogicalLeft, + const Length& marginLogicalRight, LogicalExtentComputedValues&) const; void computePositionedLogicalHeightUsing(Length logicalHeightLength, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalHeight, LayoutUnit bordersPlusPadding, LayoutUnit logicalHeight, - Length logicalTop, Length logicalBottom, Length marginLogicalTop, Length marginLogicalBottom, - LogicalExtentComputedValues&) const; + const Length& logicalTop, const Length& logicalBottom, const Length& marginLogicalTop, + const Length& marginLogicalBottom, LogicalExtentComputedValues&) const; void computePositionedLogicalHeightReplaced(LogicalExtentComputedValues&) const; void computePositionedLogicalWidthReplaced(LogicalExtentComputedValues&) const; @@ -687,10 +704,22 @@ private: virtual LayoutRect frameRectForStickyPositioning() const OVERRIDE FINAL { return frameRect(); } + RenderBoxRareData& ensureRareData() + { + if (!m_rareData) + m_rareData = adoptPtr(new RenderBoxRareData()); + return *m_rareData.get(); + } + private: // The width/height of the contents + borders + padding. The x/y location is relative to our container (which is not always our parent). LayoutRect m_frameRect; + // Our intrinsic height, used for min-height: min-content etc. Maintained by + // updateLogicalHeight. This is logicalHeight() before it is clamped to + // min/max. + mutable LayoutUnit m_intrinsicContentLogicalHeight; + protected: LayoutBoxExtent m_marginBox; @@ -700,16 +729,11 @@ protected: // The preferred logical width of the element if it never breaks any lines at all. LayoutUnit m_maxPreferredLogicalWidth; - // Our intrinsic height, used for min-height: min-content etc. Maintained by - // updateLogicalHeight. This is logicalHeight() before it is clamped to - // min/max. - LayoutUnit m_intrinsicContentLogicalHeight; - - // For inline replaced elements, the inline box that owns us. - InlineBox* m_inlineBoxWrapper; - // Our overflow information. OwnPtr<RenderOverflow> m_overflow; + +private: + OwnPtr<RenderBoxRareData> m_rareData; }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderBox, isBox()); @@ -731,27 +755,27 @@ inline RenderBox* RenderBox::parentBox() const inline RenderBox* RenderBox::firstChildBox() const { - return toRenderBox(firstChild()); + return toRenderBox(slowFirstChild()); } inline RenderBox* RenderBox::lastChildBox() const { - return toRenderBox(lastChild()); + return toRenderBox(slowLastChild()); } inline void RenderBox::setInlineBoxWrapper(InlineBox* boxWrapper) { if (boxWrapper) { - ASSERT(!m_inlineBoxWrapper); + ASSERT(!inlineBoxWrapper()); // m_inlineBoxWrapper should already be 0. Deleting it is a safeguard against security issues. // Otherwise, there will two line box wrappers keeping the reference to this renderer, and // only one will be notified when the renderer is getting destroyed. The second line box wrapper // will keep a stale reference. - if (UNLIKELY(m_inlineBoxWrapper != 0)) + if (UNLIKELY(inlineBoxWrapper() != 0)) deleteLineBoxWrapper(); } - m_inlineBoxWrapper = boxWrapper; + ensureRareData().m_inlineBoxWrapper = boxWrapper; } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderBoxModelObject.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderBoxModelObject.cpp index caef81861c4..5e56efce625 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderBoxModelObject.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderBoxModelObject.cpp @@ -26,23 +26,23 @@ #include "config.h" #include "core/rendering/RenderBoxModelObject.h" -#include "HTMLNames.h" -#include "core/html/HTMLFrameOwnerElement.h" +#include "core/HTMLNames.h" #include "core/frame/Settings.h" +#include "core/html/HTMLFrameOwnerElement.h" #include "core/page/scrolling/ScrollingConstraints.h" -#include "core/rendering/CompositedLayerMapping.h" #include "core/rendering/ImageQualityController.h" #include "core/rendering/RenderBlock.h" +#include "core/rendering/RenderFlowThread.h" #include "core/rendering/RenderGeometryMap.h" #include "core/rendering/RenderInline.h" #include "core/rendering/RenderLayer.h" -#include "core/rendering/RenderLayerCompositor.h" -#include "core/rendering/RenderNamedFlowThread.h" #include "core/rendering/RenderRegion.h" #include "core/rendering/RenderView.h" +#include "core/rendering/compositing/CompositedLayerMapping.h" +#include "core/rendering/compositing/RenderLayerCompositor.h" #include "core/rendering/style/ShadowList.h" #include "platform/geometry/TransformState.h" -#include "platform/graphics/DrawLooper.h" +#include "platform/graphics/DrawLooperBuilder.h" #include "platform/graphics/GraphicsContextStateSaver.h" #include "platform/graphics/Path.h" #include "wtf/CurrentTime.h" @@ -100,51 +100,9 @@ bool RenderBoxModelObject::hasAcceleratedCompositing() const return view()->compositor()->hasAcceleratedCompositing(); } -bool RenderBoxModelObject::startTransition(double timeOffset, CSSPropertyID propertyId, const RenderStyle* fromStyle, const RenderStyle* toStyle) -{ - ASSERT(hasLayer()); - ASSERT(compositingState() == PaintsIntoOwnBacking); - return layer()->compositedLayerMapping()->startTransition(timeOffset, propertyId, fromStyle, toStyle); -} - -void RenderBoxModelObject::transitionPaused(double timeOffset, CSSPropertyID propertyId) -{ - ASSERT(hasLayer()); - ASSERT(compositingState() == PaintsIntoOwnBacking); - layer()->compositedLayerMapping()->transitionPaused(timeOffset, propertyId); -} - -void RenderBoxModelObject::transitionFinished(CSSPropertyID propertyId) -{ - ASSERT(hasLayer()); - ASSERT(compositingState() == PaintsIntoOwnBacking); - layer()->compositedLayerMapping()->transitionFinished(propertyId); -} - -bool RenderBoxModelObject::startAnimation(double timeOffset, const CSSAnimationData* animation, const KeyframeList& keyframes) -{ - ASSERT(hasLayer()); - ASSERT(compositingState() == PaintsIntoOwnBacking); - return layer()->compositedLayerMapping()->startAnimation(timeOffset, animation, keyframes); -} - -void RenderBoxModelObject::animationPaused(double timeOffset, const String& name) -{ - ASSERT(hasLayer()); - ASSERT(compositingState() == PaintsIntoOwnBacking); - layer()->compositedLayerMapping()->animationPaused(timeOffset, name); -} - -void RenderBoxModelObject::animationFinished(const String& name) +InterpolationQuality RenderBoxModelObject::chooseInterpolationQuality(GraphicsContext* context, Image* image, const void* layer, const LayoutSize& size) { - ASSERT(hasLayer()); - ASSERT(compositingState() == PaintsIntoOwnBacking); - layer()->compositedLayerMapping()->animationFinished(name); -} - -bool RenderBoxModelObject::shouldPaintAtLowQuality(GraphicsContext* context, Image* image, const void* layer, const LayoutSize& size) -{ - return ImageQualityController::imageQualityController()->shouldPaintAtLowQuality(context, this, image, layer, size); + return ImageQualityController::imageQualityController()->chooseInterpolationQuality(context, this, image, layer, size); } RenderBoxModelObject::RenderBoxModelObject(ContainerNode* node) @@ -170,12 +128,19 @@ void RenderBoxModelObject::willBeDestroyed() RenderLayerModelObject::willBeDestroyed(); } +bool RenderBoxModelObject::calculateHasBoxDecorations() const +{ + RenderStyle* styleToUse = style(); + ASSERT(styleToUse); + return hasBackground() || styleToUse->hasBorder() || styleToUse->hasAppearance() || styleToUse->boxShadow(); +} + void RenderBoxModelObject::updateFromStyle() { RenderLayerModelObject::updateFromStyle(); RenderStyle* styleToUse = style(); - setHasBoxDecorations(hasBackground() || styleToUse->hasBorder() || styleToUse->hasAppearance() || styleToUse->boxShadow()); + setHasBoxDecorations(calculateHasBoxDecorations()); setInline(styleToUse->isDisplayInlineType()); setPositionState(styleToUse->position()); setHorizontalWritingMode(styleToUse->isHorizontalWritingMode()); @@ -222,6 +187,11 @@ bool RenderBoxModelObject::hasAutoHeightOrContainingBlockWithAutoHeight() const if (cb->isTableCell()) return false; + // Match RenderBox::availableLogicalHeightUsing by special casing + // the render view. The available height is taken from the frame. + if (cb->isRenderView()) + return false; + if (!cb->style()->logicalHeight().isAuto() || (!cb->style()->logicalTop().isAuto() && !cb->style()->logicalBottom().isAuto())) return false; @@ -240,11 +210,11 @@ LayoutSize RenderBoxModelObject::relativePositionOffset() const // call availableWidth on our containing block. if (!style()->left().isAuto()) { if (!style()->right().isAuto() && !containingBlock->style()->isLeftToRightDirection()) - offset.setWidth(-valueForLength(style()->right(), containingBlock->availableWidth(), view())); + offset.setWidth(-valueForLength(style()->right(), containingBlock->availableWidth())); else - offset.expand(valueForLength(style()->left(), containingBlock->availableWidth(), view()), 0); + offset.expand(valueForLength(style()->left(), containingBlock->availableWidth()), 0); } else if (!style()->right().isAuto()) { - offset.expand(-valueForLength(style()->right(), containingBlock->availableWidth(), view()), 0); + offset.expand(-valueForLength(style()->right(), containingBlock->availableWidth()), 0); } // If the containing block of a relatively positioned element does not @@ -257,13 +227,13 @@ LayoutSize RenderBoxModelObject::relativePositionOffset() const && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight() || !style()->top().isPercent() || containingBlock->stretchesToViewport())) - offset.expand(0, valueForLength(style()->top(), containingBlock->availableHeight(), view())); + offset.expand(0, valueForLength(style()->top(), containingBlock->availableHeight())); else if (!style()->bottom().isAuto() && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight() || !style()->bottom().isPercent() || containingBlock->stretchesToViewport())) - offset.expand(0, -valueForLength(style()->bottom(), containingBlock->availableHeight(), view())); + offset.expand(0, -valueForLength(style()->bottom(), containingBlock->availableHeight())); return offset; } @@ -276,7 +246,7 @@ LayoutPoint RenderBoxModelObject::adjustedPositionRelativeToOffsetParent(const L return LayoutPoint(); LayoutPoint referencePoint = startPoint; - referencePoint.move(parent()->offsetForColumns(referencePoint)); + referencePoint.move(parent()->columnOffset(referencePoint)); // 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 @@ -294,24 +264,17 @@ LayoutPoint RenderBoxModelObject::adjustedPositionRelativeToOffsetParent(const L else if (isStickyPositioned()) referencePoint.move(stickyPositionOffset()); - // CSS regions specification says that region flows should return the body element as their offsetParent. - // Since we will bypass the body’s renderer anyway, just end the loop if we encounter a region flow (named flow thread). - // See http://dev.w3.org/csswg/css-regions/#cssomview-offset-attributes RenderObject* current; - for (current = parent(); current != offsetParent && !current->isRenderNamedFlowThread() && current->parent(); current = current->parent()) { + for (current = parent(); current != offsetParent && current->parent(); current = current->parent()) { // FIXME: What are we supposed to do inside SVG content? if (!isOutOfFlowPositioned()) { if (current->isBox() && !current->isTableRow()) referencePoint.moveBy(toRenderBox(current)->topLeftLocation()); - referencePoint.move(current->parent()->offsetForColumns(referencePoint)); + referencePoint.move(current->parent()->columnOffset(referencePoint)); } } - // Compute the offset position for elements inside named flow threads for which the offsetParent was the body. - // See https://code.google.com/p/chromium/issues/detail?id=242168 - if (current->isRenderNamedFlowThread()) - referencePoint = toRenderNamedFlowThread(current)->adjustedPositionRelativeToOffsetParent(*this, referencePoint); - else if (offsetParent->isBox() && offsetParent->isBody() && !offsetParent->isPositioned()) + if (offsetParent->isBox() && offsetParent->isBody() && !offsetParent->isPositioned()) referencePoint.moveBy(toRenderBox(offsetParent)->topLeftLocation()); } } @@ -319,7 +282,7 @@ LayoutPoint RenderBoxModelObject::adjustedPositionRelativeToOffsetParent(const L return referencePoint; } -void RenderBoxModelObject::computeStickyPositionConstraints(StickyPositionViewportConstraints& constraints, const FloatRect& viewportRect) const +void RenderBoxModelObject::computeStickyPositionConstraints(StickyPositionViewportConstraints& constraints, const FloatRect& constrainingRect) const { RenderBlock* containingBlock = this->containingBlock(); @@ -328,10 +291,10 @@ void RenderBoxModelObject::computeStickyPositionConstraints(StickyPositionViewpo // Sticky positioned element ignore any override logical width on the containing block (as they don't call // containingBlockLogicalWidthForContent). It's unclear whether this is totally fine. - LayoutBoxExtent minMargin(minimumValueForLength(style()->marginTop(), maxWidth, view()), - minimumValueForLength(style()->marginRight(), maxWidth, view()), - minimumValueForLength(style()->marginBottom(), maxWidth, view()), - minimumValueForLength(style()->marginLeft(), maxWidth, view())); + LayoutBoxExtent minMargin(minimumValueForLength(style()->marginTop(), maxWidth), + minimumValueForLength(style()->marginRight(), maxWidth), + minimumValueForLength(style()->marginBottom(), maxWidth), + minimumValueForLength(style()->marginLeft(), maxWidth)); // Compute the container-relative area within which the sticky element is allowed to move. containerContentRect.contract(minMargin); @@ -347,40 +310,81 @@ void RenderBoxModelObject::computeStickyPositionConstraints(StickyPositionViewpo // Map to the view to avoid including page scale factor. FloatRect absContainerFrame = containingBlock->localToContainerQuad(FloatRect(FloatPoint(), containingBlock->size()), view()).boundingBox(); + if (containingBlock->hasOverflowClip()) { + IntSize scrollOffset = containingBlock->layer()->scrollableArea()->adjustedScrollOffset(); + stickyLocation -= scrollOffset; + } + // We can't call localToAbsolute on |this| because that will recur. FIXME: For now, assume that |this| is not transformed. FloatRect absoluteStickyBoxRect(absContainerFrame.location() + stickyLocation, flippedStickyBoxRect.size()); constraints.setAbsoluteStickyBoxRect(absoluteStickyBoxRect); - if (!style()->left().isAuto()) { - constraints.setLeftOffset(valueForLength(style()->left(), viewportRect.width(), view())); + float horizontalOffsets = constraints.rightOffset() + constraints.leftOffset(); + bool skipRight = false; + bool skipLeft = false; + if (!style()->left().isAuto() && !style()->right().isAuto()) { + if (horizontalOffsets > containerContentRect.width().toFloat() + || horizontalOffsets + containerContentRect.width().toFloat() > constrainingRect.width()) { + skipRight = style()->isLeftToRightDirection(); + skipLeft = !skipRight; + } + } + + if (!style()->left().isAuto() && !skipLeft) { + constraints.setLeftOffset(floatValueForLength(style()->left(), constrainingRect.width())); constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeLeft); } - if (!style()->right().isAuto()) { - constraints.setRightOffset(valueForLength(style()->right(), viewportRect.width(), view())); + if (!style()->right().isAuto() && !skipRight) { + constraints.setRightOffset(floatValueForLength(style()->right(), constrainingRect.width())); constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeRight); } + bool skipBottom = false; + // FIXME(ostap): Exclude top or bottom edge offset depending on the writing mode when related + // sections are fixed in spec: http://lists.w3.org/Archives/Public/www-style/2014May/0286.html + float verticalOffsets = constraints.topOffset() + constraints.bottomOffset(); + if (!style()->top().isAuto() && !style()->bottom().isAuto()) { + if (verticalOffsets > containerContentRect.height().toFloat() + || verticalOffsets + containerContentRect.height().toFloat() > constrainingRect.height()) { + skipBottom = true; + } + } + if (!style()->top().isAuto()) { - constraints.setTopOffset(valueForLength(style()->top(), viewportRect.height(), view())); + constraints.setTopOffset(floatValueForLength(style()->top(), constrainingRect.height())); constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeTop); } - if (!style()->bottom().isAuto()) { - constraints.setBottomOffset(valueForLength(style()->bottom(), viewportRect.height(), view())); + if (!style()->bottom().isAuto() && !skipBottom) { + constraints.setBottomOffset(floatValueForLength(style()->bottom(), constrainingRect.height())); constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeBottom); } } LayoutSize RenderBoxModelObject::stickyPositionOffset() const { - LayoutRect viewportRect = view()->frameView()->viewportConstrainedVisibleContentRect(); + FloatRect constrainingRect; + + ASSERT(hasLayer()); + RenderLayer* enclosingClippingLayer = layer()->enclosingOverflowClipLayer(ExcludeSelf); + if (enclosingClippingLayer) { + RenderBox* enclosingClippingBox = toRenderBox(enclosingClippingLayer->renderer()); + LayoutRect clipRect = enclosingClippingBox->overflowClipRect(LayoutPoint()); + clipRect.move(enclosingClippingBox->paddingLeft(), enclosingClippingBox->paddingTop()); + clipRect.contract(LayoutSize(enclosingClippingBox->paddingLeft() + enclosingClippingBox->paddingRight(), + enclosingClippingBox->paddingTop() + enclosingClippingBox->paddingBottom())); + constrainingRect = enclosingClippingBox->localToContainerQuad(FloatRect(clipRect), view()).boundingBox(); + } else { + LayoutRect viewportRect = view()->frameView()->viewportConstrainedVisibleContentRect(); + constrainingRect = viewportRect; + } StickyPositionViewportConstraints constraints; - computeStickyPositionConstraints(constraints, viewportRect); + computeStickyPositionConstraints(constraints, constrainingRect); // The sticky offset is physical, so we can just return the delta computed in absolute coords (though it may be wrong with transforms). - return LayoutSize(constraints.computeStickyOffset(viewportRect)); + return LayoutSize(constraints.computeStickyOffset(constrainingRect)); } LayoutSize RenderBoxModelObject::offsetForInFlowPosition() const @@ -418,24 +422,20 @@ int RenderBoxModelObject::pixelSnappedOffsetHeight() const return snapSizeToPixel(offsetHeight(), offsetTop()); } -LayoutUnit RenderBoxModelObject::computedCSSPadding(Length padding) const +LayoutUnit RenderBoxModelObject::computedCSSPadding(const Length& padding) const { LayoutUnit w = 0; - RenderView* renderView = 0; if (padding.isPercent()) w = containingBlockLogicalWidthForContent(); - else if (padding.isViewportPercentage()) - renderView = view(); - return minimumValueForLength(padding, w, renderView); + return minimumValueForLength(padding, w); } RoundedRect RenderBoxModelObject::getBackgroundRoundedRect(const LayoutRect& borderRect, InlineFlowBox* box, LayoutUnit inlineBoxWidth, LayoutUnit inlineBoxHeight, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const { - RenderView* renderView = view(); - RoundedRect border = style()->getRoundedBorderFor(borderRect, renderView, includeLogicalLeftEdge, includeLogicalRightEdge); + RoundedRect border = style()->getRoundedBorderFor(borderRect, includeLogicalLeftEdge, includeLogicalRightEdge); if (box && (box->nextLineBox() || box->prevLineBox())) { - RoundedRect segmentBorder = style()->getRoundedBorderFor(LayoutRect(0, 0, inlineBoxWidth, inlineBoxHeight), renderView, includeLogicalLeftEdge, includeLogicalRightEdge); + RoundedRect segmentBorder = style()->getRoundedBorderFor(LayoutRect(0, 0, inlineBoxWidth, inlineBoxHeight), includeLogicalLeftEdge, includeLogicalRightEdge); border.setRadii(segmentBorder.radii()); } @@ -474,6 +474,8 @@ void RenderBoxModelObject::clipRoundedInnerRect(GraphicsContext * context, const } } +// FIXME: See crbug.com/382491. The use of getCTM in this context is incorrect because the matrix returned does not +// include scales applied at raster time, such as the device zoom. static LayoutRect shrinkRectByOnePixel(GraphicsContext* context, const LayoutRect& rect) { LayoutRect shrunkRect = rect; @@ -510,8 +512,8 @@ static void applyBoxShadowForBackground(GraphicsContext* context, const RenderOb if (boxShadow.style() != Normal) continue; FloatSize shadowOffset(boxShadow.x(), boxShadow.y()); - context->setShadow(shadowOffset, boxShadow.blur(), renderer->resolveColor(boxShadow.color()), - DrawLooper::ShadowRespectsTransforms, DrawLooper::ShadowIgnoresAlpha); + context->setShadow(shadowOffset, boxShadow.blur(), boxShadow.color(), + DrawLooperBuilder::ShadowRespectsTransforms, DrawLooperBuilder::ShadowIgnoresAlpha); return; } } @@ -529,11 +531,11 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co bool hasRoundedBorder = style()->hasBorderRadius() && (includeLeftEdge || includeRightEdge); bool clippedWithLocalScrolling = hasOverflowClip() && bgLayer->attachment() == LocalBackgroundAttachment; bool isBorderFill = bgLayer->clip() == BorderFillBox; - bool isRoot = this->isRoot(); + bool isRoot = this->isDocumentElement(); Color bgColor = color; StyleImage* bgImage = bgLayer->image(); - bool shouldPaintBackgroundImage = bgImage && bgImage->canRender(this, style()->effectiveZoom()); + bool shouldPaintBackgroundImage = bgImage && bgImage->canRender(*this, style()->effectiveZoom()); bool forceBackgroundToWhite = false; if (document().printing()) { @@ -552,14 +554,14 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co // while rendering.) if (forceBackgroundToWhite) { // Note that we can't reuse this variable below because the bgColor might be changed - bool shouldPaintBackgroundColor = !bgLayer->next() && bgColor.isValid() && bgColor.alpha(); + bool shouldPaintBackgroundColor = !bgLayer->next() && bgColor.alpha(); if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) { bgColor = Color::white; shouldPaintBackgroundImage = false; } } - bool colorVisible = bgColor.isValid() && bgColor.alpha(); + bool colorVisible = bgColor.alpha(); // Fast path for drawing simple color backgrounds. if (!isRoot && !clippedWithLocalScrolling && !shouldPaintBackgroundImage && isBorderFill && !bgLayer->next()) { @@ -571,7 +573,7 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co if (boxShadowShouldBeAppliedToBackground) applyBoxShadowForBackground(context, this); - if (hasRoundedBorder && bleedAvoidance != BackgroundBleedUseTransparencyLayer) { + if (hasRoundedBorder && bleedAvoidance != BackgroundBleedClipBackground) { RoundedRect border = backgroundRoundedRectAdjustedForBleedAvoidance(context, rect, bleedAvoidance, box, boxSize, includeLeftEdge, includeRightEdge); if (border.isRenderable()) context->fillRoundedRect(border, bgColor); @@ -588,8 +590,8 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co return; } - // BorderFillBox radius clipping is taken care of by BackgroundBleedUseTransparencyLayer - bool clipToBorderRadius = hasRoundedBorder && !(isBorderFill && bleedAvoidance == BackgroundBleedUseTransparencyLayer); + // BorderFillBox radius clipping is taken care of by BackgroundBleedClipBackground + bool clipToBorderRadius = hasRoundedBorder && !(isBorderFill && bleedAvoidance == BackgroundBleedClipBackground); GraphicsContextStateSaver clipToBorderStateSaver(*context, clipToBorderRadius); if (clipToBorderRadius) { RoundedRect border = isBorderFill ? backgroundRoundedRectAdjustedForBleedAvoidance(context, rect, bleedAvoidance, box, boxSize, includeLeftEdge, includeRightEdge) : getBackgroundRoundedRect(rect, box, boxSize.width(), boxSize.height(), includeLeftEdge, includeRightEdge); @@ -614,7 +616,7 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co if (clippedWithLocalScrolling) { // Clip to the overflow area. RenderBox* thisBox = toRenderBox(this); - context->clip(thisBox->overflowClipRect(rect.location(), paintInfo.renderRegion)); + context->clip(thisBox->overflowClipRect(rect.location())); // Adjust the paint rect to reflect a scrolled content box with borders at the ends. IntSize offset = thisBox->scrolledContentOffset(); @@ -669,10 +671,10 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co bool isOpaqueRoot = false; if (isRoot) { isOpaqueRoot = true; - if (!bgLayer->next() && !(bgColor.isValid() && bgColor.alpha() == 255) && view()->frameView()) { + if (!bgLayer->next() && bgColor.hasAlpha() && view()->frameView()) { Element* ownerElement = document().ownerElement(); if (ownerElement) { - if (!ownerElement->hasTagName(frameTag)) { + if (!isHTMLFrameElement(*ownerElement)) { // Locate the <body> element using the DOM. This is easier than trying // to crawl around a render tree with potential :before/:after content and // anonymous blocks created by inline <body> tags etc. We can locate the <body> @@ -698,7 +700,7 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co if (!bgLayer->next()) { IntRect backgroundRect(pixelSnappedIntRect(scrolledPaintRect)); bool boxShadowShouldBeAppliedToBackground = this->boxShadowShouldBeAppliedToBackground(bleedAvoidance, box); - if (boxShadowShouldBeAppliedToBackground || !shouldPaintBackgroundImage || !bgLayer->hasOpaqueImage(this) || !bgLayer->hasRepeatXY()) { + if (boxShadowShouldBeAppliedToBackground || !shouldPaintBackgroundImage || !bgLayer->hasOpaqueImage(this) || !bgLayer->hasRepeatXY() || (isOpaqueRoot && !toRenderBox(this)->height())) { if (!boxShadowShouldBeAppliedToBackground) backgroundRect.intersect(paintInfo.rect); @@ -730,17 +732,20 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co // no progressive loading of the background image if (shouldPaintBackgroundImage) { BackgroundImageGeometry geometry; - calculateBackgroundImageGeometry(bgLayer, scrolledPaintRect, geometry, backgroundObject); + calculateBackgroundImageGeometry(paintInfo.paintContainer(), bgLayer, scrolledPaintRect, geometry, backgroundObject); geometry.clip(paintInfo.rect); if (!geometry.destRect().isEmpty()) { CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer->composite() : op; RenderObject* clientForBackgroundImage = backgroundObject ? backgroundObject : this; RefPtr<Image> image = bgImage->image(clientForBackgroundImage, geometry.tileSize()); - bool useLowQualityScaling = shouldPaintAtLowQuality(context, image.get(), bgLayer, geometry.tileSize()); + InterpolationQuality interpolationQuality = chooseInterpolationQuality(context, image.get(), bgLayer, geometry.tileSize()); if (bgLayer->maskSourceType() == MaskLuminance) context->setColorFilter(ColorFilterLuminanceToAlpha); + InterpolationQuality previousInterpolationQuality = context->imageInterpolationQuality(); + context->setImageInterpolationQuality(interpolationQuality); context->drawTiledImage(image.get(), geometry.destRect(), geometry.relativePhase(), geometry.tileSize(), - compositeOp, useLowQualityScaling, bgLayer->blendMode(), geometry.spaceSize()); + compositeOp, bgLayer->blendMode(), geometry.spaceSize()); + context->setImageInterpolationQuality(previousInterpolationQuality); } } @@ -754,11 +759,11 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co // Now draw the text into the mask. We do this by painting using a special paint phase that signals to // InlineTextBoxes that they should just add their contents to the clip. - PaintInfo info(context, maskRect, PaintPhaseTextClip, PaintBehaviorForceBlackText, 0, paintInfo.renderRegion); + PaintInfo info(context, maskRect, PaintPhaseTextClip, PaintBehaviorForceBlackText, 0); context->setCompositeOperation(CompositeSourceOver); if (box) { - RootInlineBox* root = box->root(); - box->paint(info, LayoutPoint(scrolledPaintRect.x() - box->x(), scrolledPaintRect.y() - box->y()), root->lineTop(), root->lineBottom()); + RootInlineBox& root = box->root(); + box->paint(info, LayoutPoint(scrolledPaintRect.x() - box->x(), scrolledPaintRect.y() - box->y()), root.lineTop(), root.lineBottom()); } else { LayoutSize localOffset = isBox() ? toRenderBox(this)->locationOffset() : LayoutSize(); paint(info, scrolledPaintRect.location() - localOffset); @@ -829,18 +834,10 @@ IntSize RenderBoxModelObject::calculateImageIntrinsicDimensions(StyleImage* imag FloatSize intrinsicRatio; 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. + ASSERT(!intrinsicWidth.isPercent()); + ASSERT(!intrinsicHeight.isPercent()); - // 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); - } - - IntSize resolvedSize(intrinsicWidth.isFixed() ? intrinsicWidth.value() : 0, intrinsicHeight.isFixed() ? intrinsicHeight.value() : 0); + IntSize resolvedSize(intrinsicWidth.value(), intrinsicHeight.value()); IntSize minimumSize(resolvedSize.width() > 0 ? 1 : 0, resolvedSize.height() > 0 ? 1 : 0); if (shouldScaleOrNot == ScaleByEffectiveZoom) resolvedSize.scale(style()->effectiveZoom()); @@ -880,7 +877,6 @@ IntSize RenderBoxModelObject::calculateFillTileSize(const FillLayer* fillLayer, IntSize imageIntrinsicSize = calculateImageIntrinsicDimensions(image, positioningAreaSize, ScaleByEffectiveZoom); imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScaleFactor()); - RenderView* renderView = view(); switch (type) { case SizeLength: { LayoutSize tileSize = positioningAreaSize; @@ -890,13 +886,13 @@ IntSize RenderBoxModelObject::calculateFillTileSize(const FillLayer* fillLayer, if (layerWidth.isFixed()) tileSize.setWidth(layerWidth.value()); - else if (layerWidth.isPercent() || layerWidth.isViewportPercentage()) - tileSize.setWidth(valueForLength(layerWidth, positioningAreaSize.width(), renderView)); + else if (layerWidth.isPercent()) + tileSize.setWidth(valueForLength(layerWidth, positioningAreaSize.width())); if (layerHeight.isFixed()) tileSize.setHeight(layerHeight.value()); - else if (layerHeight.isPercent() || layerHeight.isViewportPercentage()) - tileSize.setHeight(valueForLength(layerHeight, positioningAreaSize.height(), renderView)); + else if (layerHeight.isPercent()) + tileSize.setHeight(valueForLength(layerHeight, positioningAreaSize.height())); applySubPixelHeuristicForTileSize(tileSize, positioningAreaSize); @@ -972,7 +968,7 @@ IntPoint RenderBoxModelObject::BackgroundImageGeometry::relativePhase() const bool RenderBoxModelObject::fixedBackgroundPaintsInLocalCoordinates() const { - if (!isRoot()) + if (!isDocumentElement()) return false; if (view()->frameView() && view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers) @@ -996,8 +992,8 @@ static inline int getSpace(int areaSize, int tileSize) return space; } -void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fillLayer, const LayoutRect& paintRect, - BackgroundImageGeometry& geometry, RenderObject* backgroundObject) +void RenderBoxModelObject::calculateBackgroundImageGeometry(const RenderLayerModelObject* paintContainer, const FillLayer* fillLayer, const LayoutRect& paintRect, + BackgroundImageGeometry& geometry, RenderObject* backgroundObject) const { LayoutUnit left = 0; LayoutUnit top = 0; @@ -1006,17 +1002,18 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fil // Determine the background positioning area and set destRect to the background painting area. // destRect will be adjusted later if the background is non-repeating. + // FIXME: transforms spec says that fixed backgrounds behave like scroll inside transforms. bool fixedAttachment = fillLayer->attachment() == FixedBackgroundAttachment; -#if ENABLE(FAST_MOBILE_SCROLLING) - if (view()->frameView() && view()->frameView()->canBlitOnScroll()) { + if (RuntimeEnabledFeatures::fastMobileScrollingEnabled() + && view()->frameView() + && view()->frameView()->shouldAttemptToScrollUsingFastPath()) { // As a side effect of an optimization to blit on scroll, we do not honor the CSS // property "background-attachment: fixed" because it may result in rendering // artifacts. Note, these artifacts only appear if we are blitting on scroll of // a page that has fixed background images. fixedAttachment = false; } -#endif if (!fixedAttachment) { geometry.setDestRect(snappedPaintRect); @@ -1040,35 +1037,41 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fil // The background of the box generated by the root element covers the entire canvas including // its margins. Since those were added in already, we have to factor them out when computing // the background positioning area. - if (isRoot()) { + if (isDocumentElement()) { positioningAreaSize = pixelSnappedIntSize(toRenderBox(this)->size() - LayoutSize(left + right, top + bottom), toRenderBox(this)->location()); left += marginLeft(); top += marginTop(); } else positioningAreaSize = pixelSnappedIntSize(paintRect.size() - LayoutSize(left + right, top + bottom), paintRect.location()); } else { + geometry.setHasNonLocalGeometry(); + IntRect viewportRect = pixelSnappedIntRect(viewRect()); if (fixedBackgroundPaintsInLocalCoordinates()) viewportRect.setLocation(IntPoint()); else if (FrameView* frameView = view()->frameView()) viewportRect.setLocation(IntPoint(frameView->scrollOffsetForFixedPosition())); + if (paintContainer) { + IntPoint absoluteContainerOffset = roundedIntPoint(paintContainer->localToAbsolute(FloatPoint())); + viewportRect.moveBy(-absoluteContainerOffset); + } + geometry.setDestRect(pixelSnappedIntRect(viewportRect)); positioningAreaSize = geometry.destRect().size(); } - RenderObject* clientForBackgroundImage = backgroundObject ? backgroundObject : this; + const RenderObject* clientForBackgroundImage = backgroundObject ? backgroundObject : this; IntSize fillTileSize = calculateFillTileSize(fillLayer, positioningAreaSize); fillLayer->image()->setContainerSizeForRenderer(clientForBackgroundImage, fillTileSize, style()->effectiveZoom()); geometry.setTileSize(fillTileSize); EFillRepeat backgroundRepeatX = fillLayer->repeatX(); EFillRepeat backgroundRepeatY = fillLayer->repeatY(); - RenderView* renderView = view(); int availableWidth = positioningAreaSize.width() - geometry.tileSize().width(); int availableHeight = positioningAreaSize.height() - geometry.tileSize().height(); - LayoutUnit computedXPosition = minimumValueForLength(fillLayer->xPosition(), availableWidth, renderView, true); + LayoutUnit computedXPosition = roundedMinimumValueForLength(fillLayer->xPosition(), availableWidth); if (backgroundRepeatX == RoundFill && positioningAreaSize.width() > 0 && fillTileSize.width() > 0) { long nrTiles = max(1l, lroundf((float)positioningAreaSize.width() / fillTileSize.width())); @@ -1082,7 +1085,7 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fil geometry.setSpaceSize(IntSize()); } - LayoutUnit computedYPosition = minimumValueForLength(fillLayer->yPosition(), availableHeight, renderView, true); + LayoutUnit computedYPosition = roundedMinimumValueForLength(fillLayer->yPosition(), availableHeight); if (backgroundRepeatY == RoundFill && positioningAreaSize.height() > 0 && fillTileSize.height() > 0) { long nrTiles = max(1l, lroundf((float)positioningAreaSize.height() / fillTileSize.height())); @@ -1104,7 +1107,7 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fil int actualWidth = geometry.tileSize().width() + space; if (space >= 0) { - computedXPosition = minimumValueForLength(Length(), availableWidth, renderView, true); + computedXPosition = roundedMinimumValueForLength(Length(), availableWidth); geometry.setSpaceSize(IntSize(space, 0)); geometry.setPhaseX(actualWidth ? actualWidth - roundToInt(computedXPosition + left) % actualWidth : 0); } else { @@ -1125,7 +1128,7 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fil int actualHeight = geometry.tileSize().height() + space; if (space >= 0) { - computedYPosition = minimumValueForLength(Length(), availableHeight, renderView, true); + computedYPosition = roundedMinimumValueForLength(Length(), availableHeight); geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), space)); geometry.setPhaseY(actualHeight ? actualHeight - roundToInt(computedYPosition + top) % actualHeight : 0); } else { @@ -1145,13 +1148,13 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fil geometry.setDestOrigin(geometry.destRect().location()); } -static LayoutUnit computeBorderImageSide(const BorderImageLength& borderSlice, LayoutUnit borderSide, LayoutUnit imageSide, LayoutUnit boxExtent, RenderView* renderView) +static LayoutUnit computeBorderImageSide(const BorderImageLength& borderSlice, LayoutUnit borderSide, LayoutUnit imageSide, LayoutUnit boxExtent) { if (borderSlice.isNumber()) return borderSlice.number() * borderSide; if (borderSlice.length().isAuto()) return imageSide; - return valueForLength(borderSlice.length(), boxExtent, renderView); + return valueForLength(borderSlice.length(), boxExtent); } bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, const LayoutRect& rect, const RenderStyle* style, @@ -1164,7 +1167,7 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, if (!styleImage->isLoaded()) return true; // Never paint a nine-piece image incrementally, but don't paint the fallback borders either. - if (!styleImage->canRender(this, style->effectiveZoom())) + if (!styleImage->canRender(*this, style->effectiveZoom())) return false; // FIXME: border-image is broken with full page zooming when tiling has to happen, since the tiling function @@ -1180,21 +1183,20 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, int imageWidth = imageSize.width(); int imageHeight = imageSize.height(); - RenderView* renderView = view(); 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; + int topSlice = min<int>(imageHeight, valueForLength(ninePieceImage.imageSlices().top(), imageHeight)) * imageScaleFactor; + int rightSlice = min<int>(imageWidth, valueForLength(ninePieceImage.imageSlices().right(), imageWidth)) * imageScaleFactor; + int bottomSlice = min<int>(imageHeight, valueForLength(ninePieceImage.imageSlices().bottom(), imageHeight)) * imageScaleFactor; + int leftSlice = min<int>(imageWidth, valueForLength(ninePieceImage.imageSlices().left(), imageWidth)) * imageScaleFactor; ENinePieceImageRule hRule = ninePieceImage.horizontalRule(); ENinePieceImageRule vRule = ninePieceImage.verticalRule(); - int topWidth = computeBorderImageSide(ninePieceImage.borderSlices().top(), style->borderTopWidth(), topSlice, borderImageRect.height(), renderView); - int rightWidth = computeBorderImageSide(ninePieceImage.borderSlices().right(), style->borderRightWidth(), rightSlice, borderImageRect.width(), renderView); - int bottomWidth = computeBorderImageSide(ninePieceImage.borderSlices().bottom(), style->borderBottomWidth(), bottomSlice, borderImageRect.height(), renderView); - int leftWidth = computeBorderImageSide(ninePieceImage.borderSlices().left(), style->borderLeftWidth(), leftSlice, borderImageRect.width(), renderView); + int topWidth = computeBorderImageSide(ninePieceImage.borderSlices().top(), style->borderTopWidth(), topSlice, borderImageRect.height()); + int rightWidth = computeBorderImageSide(ninePieceImage.borderSlices().right(), style->borderRightWidth(), rightSlice, borderImageRect.width()); + int bottomWidth = computeBorderImageSide(ninePieceImage.borderSlices().bottom(), style->borderBottomWidth(), bottomSlice, borderImageRect.height()); + int leftWidth = computeBorderImageSide(ninePieceImage.borderSlices().left(), style->borderLeftWidth(), leftSlice, borderImageRect.width()); // 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 @@ -1744,14 +1746,18 @@ void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& BorderEdge edges[4]; getBorderEdgeInfo(edges, style, includeLogicalLeftEdge, includeLogicalRightEdge); - RoundedRect outerBorder = style->getRoundedBorderFor(rect, view(), includeLogicalLeftEdge, includeLogicalRightEdge); + RoundedRect outerBorder = style->getRoundedBorderFor(rect, includeLogicalLeftEdge, includeLogicalRightEdge); RoundedRect innerBorder = style->getRoundedInnerBorderFor(borderInnerRectAdjustedForBleedAvoidance(graphicsContext, rect, bleedAvoidance), includeLogicalLeftEdge, includeLogicalRightEdge); + if (outerBorder.rect().isEmpty()) + return; + bool haveAlphaColor = false; bool haveAllSolidEdges = true; bool haveAllDoubleEdges = true; int numEdgesVisible = 4; bool allEdgesShareColor = true; + bool allEdgesShareWidth = true; int firstVisibleEdge = -1; BorderEdgeFlags edgesToDraw = 0; @@ -1764,18 +1770,23 @@ void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& if (currEdge.presentButInvisible()) { --numEdgesVisible; allEdgesShareColor = false; + allEdgesShareWidth = false; continue; } - if (!currEdge.width) { + if (!currEdge.shouldRender()) { --numEdgesVisible; continue; } - if (firstVisibleEdge == -1) + if (firstVisibleEdge == -1) { firstVisibleEdge = i; - else if (currEdge.color != edges[firstVisibleEdge].color) - allEdgesShareColor = false; + } else { + if (currEdge.color != edges[firstVisibleEdge].color) + allEdgesShareColor = false; + if (currEdge.width != edges[firstVisibleEdge].width) + allEdgesShareWidth = false; + } if (currEdge.color.hasAlpha()) haveAlphaColor = true; @@ -1795,11 +1806,19 @@ void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& // isRenderable() check avoids issue described in https://bugs.webkit.org/show_bug.cgi?id=38787 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) + if (outerBorder.isRounded() && allEdgesShareWidth) { + + // Very fast path for single stroked round rect with circular corners + + graphicsContext->fillBetweenRoundedRects(outerBorder, innerBorder, edges[firstVisibleEdge].color); + return; + } + if (outerBorder.isRounded() && bleedAvoidance != BackgroundBleedClipBackground) path.addRoundedRect(outerBorder); else path.addRect(outerBorder.rect()); @@ -1832,12 +1851,12 @@ void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& innerThird.setRect(innerThirdRect); outerThird.setRect(outerThirdRect); - if (outerThird.isRounded() && bleedAvoidance != BackgroundBleedUseTransparencyLayer) + if (outerThird.isRounded() && bleedAvoidance != BackgroundBleedClipBackground) path.addRoundedRect(outerThird); else path.addRect(outerThird.rect()); - if (innerThird.isRounded() && bleedAvoidance != BackgroundBleedUseTransparencyLayer) + if (innerThird.isRounded() && bleedAvoidance != BackgroundBleedClipBackground) path.addRoundedRect(innerThird); else path.addRect(innerThird.rect()); @@ -1876,7 +1895,7 @@ void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& GraphicsContextStateSaver stateSaver(*graphicsContext, clipToOuterBorder); if (clipToOuterBorder) { // Clip to the inner and outer radii rects. - if (bleedAvoidance != BackgroundBleedUseTransparencyLayer) + if (bleedAvoidance != BackgroundBleedClipBackground) graphicsContext->clipRoundedRect(outerBorder); // isRenderable() check avoids issue described in https://bugs.webkit.org/show_bug.cgi?id=38787 // The inside will be clipped out later (in clipBorderSideForComplexInnerPath) @@ -1982,7 +2001,7 @@ void RenderBoxModelObject::drawBoxSideFromPath(GraphicsContext* graphicsContext, { GraphicsContextStateSaver stateSaver(*graphicsContext); LayoutRect outerRect = borderRect; - if (bleedAvoidance == BackgroundBleedUseTransparencyLayer) { + if (bleedAvoidance == BackgroundBleedClipBackground) { outerRect.inflate(1); ++outerBorderTopWidth; ++outerBorderBottomWidth; @@ -2054,7 +2073,7 @@ void RenderBoxModelObject::clipBorderSidePolygon(GraphicsContext* graphicsContex const LayoutRect& outerRect = outerBorder.rect(); const LayoutRect& innerRect = innerBorder.rect(); - FloatPoint centerPoint(innerRect.location().x() + static_cast<float>(innerRect.width()) / 2, innerRect.location().y() + static_cast<float>(innerRect.height()) / 2); + FloatPoint centerPoint(innerRect.location().x().toFloat() + innerRect.width().toFloat() / 2, innerRect.location().y().toFloat() + innerRect.height().toFloat() / 2); // For each side, create a quad that encompasses all parts of that side that may draw, // including areas inside the innerBorder. @@ -2446,7 +2465,7 @@ bool RenderBoxModelObject::boxShadowShouldBeAppliedToBackground(BackgroundBleedA return false; Color backgroundColor = resolveColor(CSSPropertyBackgroundColor); - if (!backgroundColor.isValid() || backgroundColor.hasAlpha()) + if (backgroundColor.hasAlpha()) return false; const FillLayer* lastBackgroundLayer = style()->backgroundLayers(); @@ -2476,11 +2495,11 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec return; RoundedRect border = (shadowStyle == Inset) ? s->getRoundedInnerBorderFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge) - : s->getRoundedBorderFor(paintRect, view(), includeLogicalLeftEdge, includeLogicalRightEdge); + : s->getRoundedBorderFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge); bool hasBorderRadius = s->hasBorderRadius(); bool isHorizontal = s->isHorizontalWritingMode(); - bool hasOpaqueBackground = s->visitedDependentColor(CSSPropertyBackgroundColor).isValid() && s->visitedDependentColor(CSSPropertyBackgroundColor).alpha() == 255; + bool hasOpaqueBackground = s->visitedDependentColor(CSSPropertyBackgroundColor).alpha() == 255; GraphicsContextStateSaver stateSaver(*context, false); @@ -2490,22 +2509,22 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec if (shadow.style() != shadowStyle) continue; - IntSize shadowOffset(shadow.x(), shadow.y()); - int shadowBlur = shadow.blur(); - int shadowSpread = shadow.spread(); + FloatSize shadowOffset(shadow.x(), shadow.y()); + float shadowBlur = shadow.blur(); + float shadowSpread = shadow.spread(); if (shadowOffset.isZero() && !shadowBlur && !shadowSpread) continue; - const Color& shadowColor = resolveColor(shadow.color()); + const Color& shadowColor = shadow.color(); if (shadow.style() == Normal) { - RoundedRect fillRect = border; + FloatRect fillRect = border.rect(); fillRect.inflate(shadowSpread); if (fillRect.isEmpty()) continue; - IntRect shadowRect(border.rect()); + FloatRect shadowRect(border.rect()); shadowRect.inflate(shadowBlur + shadowSpread); shadowRect.move(shadowOffset); @@ -2526,6 +2545,8 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec context->clipOutRoundedRect(rectToClipOut); } } else { + // This IntRect is correct even with fractional shadows, because it is used for the rectangle + // of the box itself, which is always pixel-aligned. IntRect rectToClipOut = border.rect(); // If the box is opaque, it is unnecessary to clip it out. However, doing so saves time @@ -2535,6 +2556,8 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec if (hasOpaqueBackground) { // FIXME: The function to decide on the policy based on the transform should be a named function. // FIXME: It's not clear if this check is right. What about integral scale factors? + // FIXME: See crbug.com/382491. The use of getCTM may also be wrong because it does not include + // device zoom applied at raster time. AffineTransform transform = context->getCTM(); if (transform.a() != 1 || (transform.d() != 1 && transform.d() != -1) || transform.b() || transform.c()) rectToClipOut.inflate(-1); @@ -2547,26 +2570,31 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec } // Draw only the shadow. - DrawLooper drawLooper; - drawLooper.addShadow(shadowOffset, shadowBlur, shadowColor, - DrawLooper::ShadowRespectsTransforms, DrawLooper::ShadowIgnoresAlpha); - context->setDrawLooper(drawLooper); + OwnPtr<DrawLooperBuilder> drawLooperBuilder = DrawLooperBuilder::create(); + drawLooperBuilder->addShadow(shadowOffset, shadowBlur, shadowColor, + DrawLooperBuilder::ShadowRespectsTransforms, DrawLooperBuilder::ShadowIgnoresAlpha); + context->setDrawLooper(drawLooperBuilder.release()); if (hasBorderRadius) { - RoundedRect influenceRect(shadowRect, border.radii()); + RoundedRect influenceRect(pixelSnappedIntRect(LayoutRect(shadowRect)), border.radii()); influenceRect.expandRadii(2 * shadowBlur + shadowSpread); if (allCornersClippedOut(influenceRect, info.rect)) - context->fillRect(fillRect.rect(), Color::black); + context->fillRect(fillRect, Color::black); else { - fillRect.expandRadii(shadowSpread); - if (!fillRect.isRenderable()) - fillRect.adjustRadii(); - context->fillRoundedRect(fillRect, Color::black); + // TODO: support non-integer shadows - crbug.com/334829 + RoundedRect roundedFillRect = border; + roundedFillRect.inflate(shadowSpread); + + roundedFillRect.expandRadii(shadowSpread); + if (!roundedFillRect.isRenderable()) + roundedFillRect.adjustRadii(); + context->fillRoundedRect(roundedFillRect, Color::black); } } else { - context->fillRect(fillRect.rect(), Color::black); + context->fillRect(fillRect, Color::black); } } else { + // The inset shadow case. GraphicsContext::Edges clippedEdges = GraphicsContext::NoEdge; if (!includeLogicalLeftEdge) { if (isHorizontal) @@ -2580,7 +2608,8 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec else clippedEdges |= GraphicsContext::BottomEdge; } - context->drawInnerShadow(border, shadowColor, shadowOffset, shadowBlur, shadowSpread, clippedEdges); + // TODO: support non-integer shadows - crbug.com/334828 + context->drawInnerShadow(border, shadowColor, flooredIntSize(shadowOffset), shadowBlur, shadowSpread, clippedEdges); } } } @@ -2640,7 +2669,7 @@ void RenderBoxModelObject::setFirstLetterRemainingText(RenderTextFragment* remai LayoutRect RenderBoxModelObject::localCaretRectForEmptyElement(LayoutUnit width, LayoutUnit textIndentOffset) { - ASSERT(!firstChild()); + ASSERT(!slowFirstChild()); // FIXME: This does not take into account either :first-line or :first-letter // However, as soon as some content is entered, the line boxes will be @@ -2708,30 +2737,22 @@ bool RenderBoxModelObject::shouldAntialiasLines(GraphicsContext* context) { // FIXME: We may want to not antialias when scaled by an integral value, // and we may want to antialias when translated by a non-integral value. + // FIXME: See crbug.com/382491. getCTM does not include scale factors applied at raster time, such + // as device zoom. return !context->getCTM().isIdentityOrTranslationOrFlipped(); } void RenderBoxModelObject::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const { // We don't expect to be called during layout. - ASSERT(!view() || !view()->layoutStateEnabled()); + ASSERT(!view() || !view()->layoutStateCachedOffsetsEnabled()); RenderObject* o = container(); if (!o) return; - // The point inside a box that's inside a region has its coordinates relative to the region, - // not the FlowThread that is its container in the RenderObject tree. - if (o->isRenderFlowThread() && isRenderBlock()) { - // FIXME: switch to Box instead of Block when we'll have range information for boxes as well, not just for blocks. - RenderRegion* startRegion; - RenderRegion* ignoredEndRegion; - toRenderFlowThread(o)->getRegionRangeForBox(toRenderBlock(this), startRegion, ignoredEndRegion); - // If there is no region to use the FlowThread, then there's no region range for the content in that FlowThread. - // An API like elementFromPoint might crash without this check. - if (startRegion) - o = startRegion; - } + if (o->isRenderFlowThread()) + transformState.move(o->columnOffset(LayoutPoint(transformState.mappedPoint()))); o->mapAbsoluteToLocalPoint(mode, transformState); @@ -2780,7 +2801,7 @@ const RenderObject* RenderBoxModelObject::pushMappingToContainer(const RenderLay if (shouldUseTransformFromContainer(container)) { TransformationMatrix t; getTransformFromContainer(container, containerOffset, t); - t.translateRight(adjustmentForSkippedAncestor.width(), adjustmentForSkippedAncestor.height()); + t.translateRight(adjustmentForSkippedAncestor.width().toFloat(), adjustmentForSkippedAncestor.height().toFloat()); geometryMap.push(this, t, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform); } else { containerOffset += adjustmentForSkippedAncestor; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderBoxModelObject.h b/chromium/third_party/WebKit/Source/core/rendering/RenderBoxModelObject.h index 31b318612b8..f308aec7ca8 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderBoxModelObject.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderBoxModelObject.h @@ -24,6 +24,7 @@ #ifndef RenderBoxModelObject_h #define RenderBoxModelObject_h +#include "core/animation/ActiveAnimations.h" #include "core/rendering/RenderLayerModelObject.h" #include "core/rendering/style/ShadowData.h" #include "platform/geometry/LayoutRect.h" @@ -38,20 +39,17 @@ typedef unsigned BorderEdgeFlags; enum BackgroundBleedAvoidance { BackgroundBleedNone, BackgroundBleedShrinkBackground, - BackgroundBleedUseTransparencyLayer, + BackgroundBleedClipBackground, BackgroundBleedBackgroundOverBorder }; enum ContentChangeType { ImageChanged, - MaskImageChanged, CanvasChanged, CanvasPixelsChanged, - VideoChanged, - FullScreenChanged + CanvasContextChanged }; -class KeyframeList; class RenderTextFragment; class StickyPositionViewportConstraints; @@ -66,7 +64,7 @@ public: LayoutSize relativePositionOffset() const; LayoutSize relativePositionLogicalOffset() const { return style()->isHorizontalWritingMode() ? relativePositionOffset() : relativePositionOffset().transposedSize(); } - void computeStickyPositionConstraints(StickyPositionViewportConstraints&, const FloatRect& viewportRect) const; + void computeStickyPositionConstraints(StickyPositionViewportConstraints&, const FloatRect& constrainingRect) const; LayoutSize stickyPositionOffset() const; LayoutSize stickyPositionLogicalOffset() const { return style()->isHorizontalWritingMode() ? stickyPositionOffset() : stickyPositionOffset().transposedSize(); } @@ -86,8 +84,6 @@ public: virtual void updateFromStyle() OVERRIDE; - virtual bool requiresLayer() const OVERRIDE { return isRoot() || isPositioned() || createsGroup() || hasClipPath() || hasTransform() || hasHiddenBackface() || hasReflection() || style()->specifiesColumns(); } - // This will work on inlines to return the bounding box of all of the lines' border boxes. virtual IntRect borderBoundingBox() const = 0; @@ -121,6 +117,9 @@ public: virtual int borderStart() const { return style()->borderStartWidth(); } virtual int borderEnd() const { return style()->borderEndWidth(); } + int borderWidth() const { return borderLeft() + borderRight(); } + int borderHeight() const { return borderTop() + borderBottom(); } + LayoutUnit borderAndPaddingStart() const { return borderStart() + paddingStart(); } LayoutUnit borderAndPaddingBefore() const { return borderBefore() + paddingBefore(); } LayoutUnit borderAndPaddingAfter() const { return borderAfter() + paddingAfter(); } @@ -176,30 +175,22 @@ public: virtual void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const OVERRIDE; virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE; - void highQualityRepaintTimerFired(Timer<RenderBoxModelObject>*); - - virtual void setSelectionState(SelectionState s); - - bool canHaveBoxInfoInRegion() const { return !isFloating() && !isReplaced() && !isInline() && !hasColumns() && !isTableCell() && isRenderBlock() && !isRenderSVGBlock(); } + virtual void setSelectionState(SelectionState) OVERRIDE; 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 CSSAnimationData*, const KeyframeList& keyframes); - void animationPaused(double timeOffset, const String& name); - void animationFinished(const String& name); - virtual void computeLayerHitTestRects(LayerHitTestRects&) const OVERRIDE; protected: - virtual void willBeDestroyed(); + virtual void willBeDestroyed() OVERRIDE; class BackgroundImageGeometry { public: + BackgroundImageGeometry() + : m_hasNonLocalGeometry(false) + { } + IntPoint destOrigin() const { return m_destOrigin; } void setDestOrigin(const IntPoint& destOrigin) { @@ -244,37 +235,43 @@ protected: void useFixedAttachment(const IntPoint& attachmentPoint); void clip(const IntRect&); + + void setHasNonLocalGeometry(bool hasNonLocalGeometry = true) { m_hasNonLocalGeometry = hasNonLocalGeometry; } + bool hasNonLocalGeometry() const { return m_hasNonLocalGeometry; } + private: IntRect m_destRect; IntPoint m_destOrigin; IntPoint m_phase; IntSize m_tileSize; IntSize m_repeatSpacing; + bool m_hasNonLocalGeometry; // Has background-attachment: fixed. Implies that we can't always cheaply compute destRect. }; LayoutPoint adjustedPositionRelativeToOffsetParent(const LayoutPoint&) const; - void calculateBackgroundImageGeometry(const FillLayer*, const LayoutRect& paintRect, BackgroundImageGeometry&, RenderObject* = 0); + bool calculateHasBoxDecorations() const; + void calculateBackgroundImageGeometry(const RenderLayerModelObject* paintContainer, const FillLayer*, const LayoutRect& paintRect, BackgroundImageGeometry&, RenderObject* = 0) const; void getBorderEdgeInfo(class BorderEdge[], const RenderStyle*, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const; bool borderObscuresBackgroundEdge(const FloatSize& contextScale) const; bool borderObscuresBackground() const; RoundedRect backgroundRoundedRectAdjustedForBleedAvoidance(GraphicsContext*, const LayoutRect&, BackgroundBleedAvoidance, InlineFlowBox*, const LayoutSize&, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const; LayoutRect borderInnerRectAdjustedForBleedAvoidance(GraphicsContext*, const LayoutRect&, BackgroundBleedAvoidance) const; - bool shouldPaintAtLowQuality(GraphicsContext*, Image*, const void*, const LayoutSize&); + InterpolationQuality chooseInterpolationQuality(GraphicsContext*, Image*, const void*, const LayoutSize&); RenderBoxModelObject* continuation() const; void setContinuation(RenderBoxModelObject*); LayoutRect localCaretRectForEmptyElement(LayoutUnit width, LayoutUnit textIndentOffset); - static bool shouldAntialiasLines(GraphicsContext*); - static void clipRoundedInnerRect(GraphicsContext*, const LayoutRect&, const RoundedRect& clipRect); bool hasAutoHeightOrContainingBlockWithAutoHeight() const; public: + static bool shouldAntialiasLines(GraphicsContext*); + // For RenderBlocks and RenderInlines with m_style->styleType() == FIRST_LETTER, this tracks their remaining text fragments RenderTextFragment* firstLetterRemainingText() const; void setFirstLetterRemainingText(RenderTextFragment*); @@ -293,7 +290,7 @@ public: } void moveAllChildrenTo(RenderBoxModelObject* toBoxModelObject, RenderObject* beforeChild, bool fullRemoveInsert = false) { - moveChildrenTo(toBoxModelObject, firstChild(), 0, beforeChild, fullRemoveInsert); + moveChildrenTo(toBoxModelObject, slowFirstChild(), 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. @@ -303,17 +300,17 @@ public: } void moveChildrenTo(RenderBoxModelObject* toBoxModelObject, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert = false); + enum ScaleByEffectiveZoomOrNot { ScaleByEffectiveZoom, DoNotScaleByEffectiveZoom }; + IntSize calculateImageIntrinsicDimensions(StyleImage*, const IntSize& scaledPositioningAreaSize, ScaleByEffectiveZoomOrNot) const; + private: - LayoutUnit computedCSSPadding(Length) const; + LayoutUnit computedCSSPadding(const Length&) const; virtual bool isBoxModelObject() const OVERRIDE FINAL { return true; } virtual LayoutRect frameRectForStickyPositioning() const = 0; IntSize calculateFillTileSize(const FillLayer*, const IntSize& scaledPositioningAreaSize) const; - enum ScaleByEffectiveZoomOrNot { ScaleByEffectiveZoom, DoNotScaleByEffectiveZoom }; - IntSize calculateImageIntrinsicDimensions(StyleImage*, const IntSize& scaledPositioningAreaSize, ScaleByEffectiveZoomOrNot) const; - RoundedRect getBackgroundRoundedRect(const LayoutRect&, InlineFlowBox*, LayoutUnit inlineBoxWidth, LayoutUnit inlineBoxHeight, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderButton.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderButton.cpp index ce1bec473ce..9b16c4af8a0 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderButton.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderButton.cpp @@ -63,7 +63,7 @@ void RenderButton::removeChild(RenderObject* oldChild) m_inner->removeChild(oldChild); } -void RenderButton::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) +void RenderButton::styleWillChange(StyleDifference diff, const RenderStyle& newStyle) { if (m_inner) { // RenderBlock::setStyle is going to apply a new style to the inner block, which @@ -71,9 +71,9 @@ void RenderButton::styleWillChange(StyleDifference diff, const RenderStyle* newS // it right below. Here we change it back to 0 to avoid getting a spurious layout hint // because of the difference. Same goes for the other properties. // FIXME: Make this hack unnecessary. - m_inner->style()->setFlexGrow(newStyle->initialFlexGrow()); - m_inner->style()->setMarginTop(newStyle->initialMargin()); - m_inner->style()->setMarginBottom(newStyle->initialMargin()); + m_inner->style()->setFlexGrow(newStyle.initialFlexGrow()); + m_inner->style()->setMarginTop(newStyle.initialMargin()); + m_inner->style()->setMarginBottom(newStyle.initialMargin()); } RenderBlock::styleWillChange(diff, newStyle); } @@ -97,6 +97,10 @@ void RenderButton::setupInnerStyle(RenderStyle* innerStyle) innerStyle->setMarginTop(Length()); innerStyle->setMarginBottom(Length()); innerStyle->setFlexDirection(style()->flexDirection()); + innerStyle->setJustifyContent(style()->justifyContent()); + innerStyle->setFlexWrap(style()->flexWrap()); + innerStyle->setAlignItems(style()->alignItems()); + innerStyle->setAlignContent(style()->alignContent()); } bool RenderButton::canHaveGeneratedChildren() const @@ -104,7 +108,7 @@ bool RenderButton::canHaveGeneratedChildren() const // Input elements can't have generated children, but button elements can. We'll // write the code assuming any other button types that might emerge in the future // can also have children. - return !node()->hasTagName(inputTag); + return !isHTMLInputElement(*node()); } LayoutRect RenderButton::controlClipRect(const LayoutPoint& additionalOffset) const diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderButton.h b/chromium/third_party/WebKit/Source/core/rendering/RenderButton.h index 33df32be802..8aaed6266c9 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderButton.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderButton.h @@ -21,13 +21,11 @@ #ifndef RenderButton_h #define RenderButton_h -#include "HTMLNames.h" +#include "core/html/HTMLInputElement.h" #include "core/rendering/RenderFlexibleBox.h" namespace WebCore { -class RenderTextFragment; - // RenderButtons are just like normal flexboxes except that they will generate an anonymous block child. // For inputs, they will also generate an anonymous RenderText and keep its style and content up // to date as the button changes. @@ -36,15 +34,16 @@ public: explicit RenderButton(Element*); virtual ~RenderButton(); - virtual const char* renderName() const { return "RenderButton"; } - virtual bool isRenderButton() const { return true; } + virtual const char* renderName() const OVERRIDE { return "RenderButton"; } + virtual bool isRenderButton() const OVERRIDE { return true; } virtual bool canBeSelectionLeaf() const OVERRIDE { return node() && node()->rendererIsEditable(); } + virtual bool canCollapseAnonymousBlockChild() const OVERRIDE { return true; } - virtual void addChild(RenderObject* newChild, RenderObject *beforeChild = 0); - virtual void removeChild(RenderObject*); - virtual void removeLeftoverAnonymousBlock(RenderBlock*) { } - virtual bool createsAnonymousWrapper() const { return true; } + virtual void addChild(RenderObject* newChild, RenderObject *beforeChild = 0) OVERRIDE; + virtual void removeChild(RenderObject*) OVERRIDE; + virtual void removeLeftoverAnonymousBlock(RenderBlock*) OVERRIDE { } + virtual bool createsAnonymousWrapper() const OVERRIDE { return true; } void setupInnerStyle(RenderStyle*); @@ -52,16 +51,16 @@ public: virtual bool canHaveWhitespaceChildren() const OVERRIDE { return true; } virtual bool canHaveGeneratedChildren() const OVERRIDE; - virtual bool hasControlClip() const { return true; } - virtual LayoutRect controlClipRect(const LayoutPoint&) const; + virtual bool hasControlClip() const OVERRIDE { return true; } + virtual LayoutRect controlClipRect(const LayoutPoint&) const OVERRIDE; virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode) const OVERRIDE; private: - virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleWillChange(StyleDifference, const RenderStyle& newStyle) OVERRIDE; + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; - virtual bool hasLineIfEmpty() const { return node() && node()->hasTagName(HTMLNames::inputTag); } + virtual bool hasLineIfEmpty() const OVERRIDE { return isHTMLInputElement(node()); } RenderBlock* m_inner; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderCombineText.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderCombineText.cpp index 75ae66dec91..2e58c5f995b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderCombineText.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderCombineText.cpp @@ -55,28 +55,31 @@ void RenderCombineText::setTextInternal(PassRefPtr<StringImpl> text) m_needsFontUpdate = true; } -float RenderCombineText::width(unsigned from, unsigned length, const Font& font, float xPosition, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const +float RenderCombineText::width(unsigned from, unsigned length, const Font& font, float xPosition, TextDirection direction, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { + if (!length) + return 0; + if (hasEmptyText()) return 0; if (m_isCombined) - return font.size(); + return font.fontDescription().computedSize(); - return RenderText::width(from, length, font, xPosition, fallbackFonts, glyphOverflow); + return RenderText::width(from, length, font, xPosition, direction, fallbackFonts, glyphOverflow); } void RenderCombineText::adjustTextOrigin(FloatPoint& textOrigin, const FloatRect& boxRect) const { if (m_isCombined) - textOrigin.move(boxRect.height() / 2 - ceilf(m_combinedTextWidth) / 2, style()->font().pixelSize()); + textOrigin.move(boxRect.height() / 2 - ceilf(m_combinedTextWidth) / 2, style()->font().fontDescription().computedPixelSize()); } void RenderCombineText::getStringToRender(int start, StringView& string, int& length) const { ASSERT(start >= 0); if (m_isCombined) { - string = StringView(originalText()); + string = StringView(m_renderingText.impl()); length = string.length(); return; } @@ -96,7 +99,7 @@ void RenderCombineText::combineText() if (style()->isHorizontalWritingMode()) return; - TextRun run = RenderBlockFlow::constructTextRun(this, originalFont(), this, style()); + TextRun run = RenderBlockFlow::constructTextRun(this, originalFont(), this, style(), style()->direction()); FontDescription description = originalFont().fontDescription(); float emWidth = description.computedSize() * textCombineMargin; bool shouldUpdateFont = false; @@ -114,7 +117,7 @@ void RenderCombineText::combineText() static const FontWidthVariant widthVariants[] = { HalfWidth, ThirdWidth, QuarterWidth }; for (size_t i = 0 ; i < WTF_ARRAY_LENGTH(widthVariants) ; ++i) { description.setWidthVariant(widthVariants[i]); - Font compressedFont = Font(description, style()->font().letterSpacing(), style()->font().wordSpacing()); + Font compressedFont = Font(description); compressedFont.update(fontSelector); float runWidth = compressedFont.width(run); if (runWidth <= emWidth) { @@ -136,6 +139,7 @@ void RenderCombineText::combineText() if (m_isCombined) { DEFINE_STATIC_LOCAL(String, objectReplacementCharacterString, (&objectReplacementCharacter, 1)); + m_renderingText = text(); RenderText::setTextInternal(objectReplacementCharacterString.impl()); } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderCombineText.h b/chromium/third_party/WebKit/Source/core/rendering/RenderCombineText.h index ce196d4c360..d15bdd75447 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderCombineText.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderCombineText.h @@ -34,17 +34,18 @@ public: void adjustTextOrigin(FloatPoint& textOrigin, const FloatRect& boxRect) const; void getStringToRender(int, StringView&, int& length) const; bool isCombined() const { return m_isCombined; } - float combinedTextWidth(const Font& font) const { return font.size(); } + float combinedTextWidth(const Font& font) const { return font.fontDescription().computedSize(); } const Font& originalFont() const { return parent()->style()->font(); } private: - virtual bool isCombineText() const { return true; } - virtual float width(unsigned from, unsigned length, const Font&, float xPosition, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; - virtual const char* renderName() const { return "RenderCombineText"; } - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - virtual void setTextInternal(PassRefPtr<StringImpl>); + virtual bool isCombineText() const OVERRIDE { return true; } + virtual float width(unsigned from, unsigned length, const Font&, float xPosition, TextDirection, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const OVERRIDE; + virtual const char* renderName() const OVERRIDE { return "RenderCombineText"; } + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; + virtual void setTextInternal(PassRefPtr<StringImpl>) OVERRIDE; float m_combinedTextWidth; + String m_renderingText; bool m_isCombined : 1; bool m_needsFontUpdate : 1; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderCounter.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderCounter.cpp index 5aac629a947..6451d43ea54 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderCounter.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderCounter.cpp @@ -22,7 +22,7 @@ #include "config.h" #include "core/rendering/RenderCounter.h" -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/dom/Document.h" #include "core/dom/Element.h" #include "core/dom/ElementTraversal.h" @@ -148,12 +148,12 @@ static bool planCounter(RenderObject& object, const AtomicString& identifier, bo return true; } if (Node* e = object.node()) { - if (e->hasTagName(olTag)) { + if (isHTMLOListElement(*e)) { value = toHTMLOListElement(e)->start(); isReset = true; return true; } - if (e->hasTagName(ulTag) || e->hasTagName(menuTag) || e->hasTagName(dirTag)) { + if (isHTMLUListElement(*e) || isHTMLMenuElement(*e) || isHTMLDirectoryElement(*e)) { value = 0; isReset = true; return true; @@ -189,8 +189,8 @@ static bool findPlaceForCounter(RenderObject& counterOwner, const AtomicString& // towards the begining of the document for counters with the same identifier as the one // we are trying to find a place for. This is the next renderer to be checked. RenderObject* currentRenderer = previousInPreOrder(counterOwner); - previousSibling = 0; - RefPtr<CounterNode> previousSiblingProtector = 0; + previousSibling = nullptr; + RefPtr<CounterNode> previousSiblingProtector = nullptr; while (currentRenderer) { CounterNode* currentCounter = makeCounterNode(*currentRenderer, identifier, false); @@ -216,7 +216,7 @@ static bool findPlaceForCounter(RenderObject& counterOwner, const AtomicString& // In these cases the identified previousSibling will be invalid as its parent is different from // our identified parent. if (previousSiblingProtector->parent() != currentCounter) - previousSiblingProtector = 0; + previousSiblingProtector = nullptr; previousSibling = previousSiblingProtector.get(); return true; @@ -307,8 +307,8 @@ static CounterNode* makeCounterNode(RenderObject& object, const AtomicString& id if (!planCounter(object, identifier, isReset, value) && !alwaysCreateCounter) return 0; - RefPtr<CounterNode> newParent = 0; - RefPtr<CounterNode> newPreviousSibling = 0; + RefPtr<CounterNode> newParent = nullptr; + RefPtr<CounterNode> newPreviousSibling = nullptr; RefPtr<CounterNode> newNode = CounterNode::create(object, isReset, value); if (findPlaceForCounter(object, identifier, isReset, newParent, newPreviousSibling)) newParent->insertAfter(newNode.get(), newPreviousSibling.get(), identifier); @@ -385,9 +385,9 @@ PassRefPtr<StringImpl> RenderCounter::originalText() const RenderObject* beforeAfterContainer = parent(); while (true) { if (!beforeAfterContainer) - return 0; + return nullptr; if (!beforeAfterContainer->isAnonymous() && !beforeAfterContainer->isPseudoElement()) - return 0; // RenderCounters are restricted to before and after pseudo elements + return nullptr; // RenderCounters are restricted to before and after pseudo elements PseudoId containerStyle = beforeAfterContainer->style()->styleType(); if ((containerStyle == BEFORE) || (containerStyle == AFTER)) break; @@ -425,7 +425,7 @@ void RenderCounter::invalidate() ASSERT(!m_counterNode); if (documentBeingDestroyed()) return; - setNeedsLayoutAndPrefWidthsRecalc(); + setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } static void destroyCounterNodeWithoutMapRemoval(const AtomicString& identifier, CounterNode* node) @@ -515,8 +515,8 @@ static void updateCounters(RenderObject& renderer) makeCounterNode(renderer, it->key, false); continue; } - RefPtr<CounterNode> newParent = 0; - RefPtr<CounterNode> newPreviousSibling = 0; + RefPtr<CounterNode> newParent = nullptr; + RefPtr<CounterNode> newPreviousSibling = nullptr; findPlaceForCounter(renderer, it->key, node->hasResetType(), newParent, newPreviousSibling); if (node != counterMap->get(it->key)) diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderCounter.h b/chromium/third_party/WebKit/Source/core/rendering/RenderCounter.h index 85cdff3b643..15d2b518cbb 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderCounter.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderCounter.h @@ -43,12 +43,12 @@ public: void updateCounter(); protected: - virtual void willBeDestroyed(); + virtual void willBeDestroyed() OVERRIDE; private: - virtual const char* renderName() const; - virtual bool isCounter() const; - virtual PassRefPtr<StringImpl> originalText() const; + virtual const char* renderName() const OVERRIDE; + virtual bool isCounter() const OVERRIDE; + virtual PassRefPtr<StringImpl> originalText() const OVERRIDE; // Removes the reference to the CounterNode associated with this renderer. // This is used to cause a counter display update when the CounterNode tree changes. diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderDeprecatedFlexibleBox.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderDeprecatedFlexibleBox.cpp index 9babdc2aae7..6a4ca48a297 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderDeprecatedFlexibleBox.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderDeprecatedFlexibleBox.cpp @@ -26,6 +26,7 @@ #include "core/rendering/RenderDeprecatedFlexibleBox.h" #include "core/frame/UseCounter.h" +#include "core/rendering/FastTextAutosizer.h" #include "core/rendering/LayoutRepainter.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderView.h" @@ -182,10 +183,10 @@ static LayoutUnit contentHeightForChild(RenderBox* child) return child->logicalHeight() - child->borderAndPaddingLogicalHeight(); } -void RenderDeprecatedFlexibleBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) +void RenderDeprecatedFlexibleBox::styleWillChange(StyleDifference diff, const RenderStyle& newStyle) { RenderStyle* oldStyle = style(); - if (oldStyle && !oldStyle->lineClamp().isNone() && newStyle->lineClamp().isNone()) + if (oldStyle && !oldStyle->lineClamp().isNone() && newStyle.lineClamp().isNone()) clearLineClamp(); RenderBlock::styleWillChange(diff, newStyle); @@ -228,19 +229,21 @@ void RenderDeprecatedFlexibleBox::computePreferredLogicalWidths() ASSERT(preferredLogicalWidthsDirty()); m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0; - if (style()->width().isFixed() && style()->width().value() > 0) - m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->width().value()); + RenderStyle* styleToUse = style(); + + if (styleToUse->width().isFixed() && styleToUse->width().value() > 0) + m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->width().value()); else computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth); - if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) { - m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value())); - m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value())); + if (styleToUse->minWidth().isFixed() && styleToUse->minWidth().value() > 0) { + m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->minWidth().value())); + m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->minWidth().value())); } - if (style()->maxWidth().isFixed()) { - m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value())); - m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value())); + if (styleToUse->maxWidth().isFixed()) { + m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->maxWidth().value())); + m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->maxWidth().value())); } LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth(); @@ -250,60 +253,57 @@ void RenderDeprecatedFlexibleBox::computePreferredLogicalWidths() clearPreferredLogicalWidthsDirty(); } -void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit) +void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren) { ASSERT(needsLayout()); if (!relayoutChildren && simplifiedLayout()) return; - LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); - LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode()); + LayoutRepainter repainter(*this, checkForPaintInvalidationDuringLayout()); - // Regions changing widths can force us to relayout our children. - RenderFlowThread* flowThread = flowThreadContainingBlock(); - if (logicalWidthChangedInRegions(flowThread)) - relayoutChildren = true; - if (updateRegionsAndShapesLogicalSize(flowThread)) - relayoutChildren = true; + { + // LayoutState needs this deliberate scope to pop before repaint + LayoutState state(*this, locationOffset()); - LayoutSize previousSize = size(); + LayoutSize previousSize = size(); - updateLogicalWidth(); - updateLogicalHeight(); + updateLogicalWidth(); + updateLogicalHeight(); - if (previousSize != size() - || (parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL - && parent()->style()->boxAlign() == BSTRETCH)) - relayoutChildren = true; + FastTextAutosizer::LayoutScope fastTextAutosizerLayoutScope(this); - setHeight(0); + if (previousSize != size() + || (parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL + && parent()->style()->boxAlign() == BSTRETCH)) + relayoutChildren = true; - m_stretchingChildren = false; + setHeight(0); - if (isHorizontal()) - layoutHorizontalBox(relayoutChildren); - else - layoutVerticalBox(relayoutChildren); + m_stretchingChildren = false; - LayoutUnit oldClientAfterEdge = clientLogicalBottom(); - updateLogicalHeight(); + if (isHorizontal()) + layoutHorizontalBox(relayoutChildren); + else + layoutVerticalBox(relayoutChildren); - if (previousSize.height() != height()) - relayoutChildren = true; + LayoutUnit oldClientAfterEdge = clientLogicalBottom(); + updateLogicalHeight(); - layoutPositionedObjects(relayoutChildren || isRoot()); + if (previousSize.height() != height()) + relayoutChildren = true; - computeRegionRangeForBlock(flowThread); + layoutPositionedObjects(relayoutChildren || isDocumentElement()); - computeOverflow(oldClientAfterEdge); + computeRegionRangeForBlock(flowThreadContainingBlock()); - statePusher.pop(); + computeOverflow(oldClientAfterEdge); + } - updateLayerTransform(); + updateLayerTransformAfterLayout(); if (view()->layoutState()->pageLogicalHeight()) - setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(this, logicalTop())); + setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(*this, logicalTop())); // Update our scrollbars if we're overflow:auto/scroll/hidden now that we know if // we overflow or not. @@ -374,7 +374,7 @@ void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren) if (child->isOutOfFlowPositioned()) continue; - SubtreeLayoutScope layoutScope(child); + SubtreeLayoutScope layoutScope(*child); if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))) layoutScope.setChildNeedsLayout(child); @@ -426,7 +426,7 @@ void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren) if (child->isOutOfFlowPositioned()) { child->containingBlock()->insertPositionedObject(child); RenderLayer* childLayer = child->layer(); - childLayer->setStaticInlinePosition(xPos); // FIXME: Not right for regions. + childLayer->setStaticInlinePosition(xPos); if (childLayer->staticBlockPosition() != yPos) { childLayer->setStaticBlockPosition(yPos); if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode())) @@ -442,7 +442,7 @@ void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren) continue; } - SubtreeLayoutScope layoutScope(child); + SubtreeLayoutScope layoutScope(*child); // We need to see if this child's height has changed, since we make block elements // fill the height of a containing box by default. @@ -501,7 +501,7 @@ void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren) bool expanding = remainingSpace > 0; unsigned int start = expanding ? lowestFlexGroup : highestFlexGroup; unsigned int end = expanding? highestFlexGroup : lowestFlexGroup; - for (unsigned int i = start; i <= end && remainingSpace; i++) { + for (unsigned i = start; i <= end && remainingSpace; i++) { // Always start off by assuming the group can get all the remaining space. LayoutUnit groupRemainingSpace = remainingSpace; do { @@ -664,7 +664,7 @@ void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren) if (child->isOutOfFlowPositioned()) { child->containingBlock()->insertPositionedObject(child); RenderLayer* childLayer = child->layer(); - childLayer->setStaticInlinePosition(borderStart() + paddingStart()); // FIXME: Not right for regions. + childLayer->setStaticInlinePosition(borderStart() + paddingStart()); if (childLayer->staticBlockPosition() != height()) { childLayer->setStaticBlockPosition(height()); if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode())) @@ -673,7 +673,7 @@ void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren) continue; } - SubtreeLayoutScope layoutScope(child); + SubtreeLayoutScope layoutScope(*child); if (!haveLineClamp && (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())))) layoutScope.setChildNeedsLayout(child); @@ -755,7 +755,7 @@ void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren) bool expanding = remainingSpace > 0; unsigned int start = expanding ? lowestFlexGroup : highestFlexGroup; unsigned int end = expanding? highestFlexGroup : lowestFlexGroup; - for (unsigned int i = start; i <= end && remainingSpace; i++) { + for (unsigned i = start; i <= end && remainingSpace; i++) { // Always start off by assuming the group can get all the remaining space. LayoutUnit groupRemainingSpace = remainingSpace; do { @@ -945,36 +945,36 @@ void RenderDeprecatedFlexibleBox::applyLineClamp(FlexBoxIterator& iterator, bool const Font& font = style(numVisibleLines == 1)->font(); // Get ellipsis width, and if the last child is an anchor, it will go after the ellipsis, so add in a space and the anchor width too - LayoutUnit totalWidth; + float totalWidth; InlineBox* anchorBox = lastLine->lastChild(); - if (anchorBox && anchorBox->renderer()->style()->isLink()) - totalWidth = anchorBox->logicalWidth() + font.width(RenderBlockFlow::constructTextRun(this, font, ellipsisAndSpace, 2, style())); + if (anchorBox && anchorBox->renderer().style()->isLink()) + totalWidth = anchorBox->logicalWidth() + font.width(RenderBlockFlow::constructTextRun(this, font, ellipsisAndSpace, 2, style(), style()->direction())); else { anchorBox = 0; - totalWidth = font.width(RenderBlockFlow::constructTextRun(this, font, &horizontalEllipsis, 1, style())); + totalWidth = font.width(RenderBlockFlow::constructTextRun(this, font, &horizontalEllipsis, 1, style(), style()->direction())); } // See if this width can be accommodated on the last visible line - RenderBlock* destBlock = toRenderBlock(lastVisibleLine->renderer()); - RenderBlock* srcBlock = toRenderBlock(lastLine->renderer()); + RenderBlockFlow& destBlock = lastVisibleLine->block(); + RenderBlockFlow& srcBlock = lastLine->block(); // FIXME: Directions of src/destBlock could be different from our direction and from one another. - if (!srcBlock->style()->isLeftToRightDirection()) + if (!srcBlock.style()->isLeftToRightDirection()) continue; - bool leftToRight = destBlock->style()->isLeftToRightDirection(); + bool leftToRight = destBlock.style()->isLeftToRightDirection(); if (!leftToRight) continue; - LayoutUnit blockRightEdge = destBlock->logicalRightOffsetForLine(lastVisibleLine->y(), false); + LayoutUnit blockRightEdge = destBlock.logicalRightOffsetForLine(lastVisibleLine->y(), false); if (!lastVisibleLine->lineCanAccommodateEllipsis(leftToRight, blockRightEdge, lastVisibleLine->x() + lastVisibleLine->logicalWidth(), totalWidth)) continue; // Let the truncation code kick in. // FIXME: the text alignment should be recomputed after the width changes due to truncation. - LayoutUnit blockLeftEdge = destBlock->logicalLeftOffsetForLine(lastVisibleLine->y(), false); - lastVisibleLine->placeEllipsis(anchorBox ? ellipsisAndSpaceStr : ellipsisStr, leftToRight, blockLeftEdge, blockRightEdge, totalWidth, anchorBox); - destBlock->setHasMarkupTruncation(true); + LayoutUnit blockLeftEdge = destBlock.logicalLeftOffsetForLine(lastVisibleLine->y(), false); + lastVisibleLine->placeEllipsis(anchorBox ? ellipsisAndSpaceStr : ellipsisStr, leftToRight, blockLeftEdge.toFloat(), blockRightEdge.toFloat(), totalWidth, anchorBox); + destBlock.setHasMarkupTruncation(true); } } @@ -1002,13 +1002,16 @@ void RenderDeprecatedFlexibleBox::placeChild(RenderBox* child, const LayoutPoint { LayoutRect oldRect = child->frameRect(); + // FIXME Investigate if this can be removed based on other flags. crbug.com/370010 + child->setMayNeedPaintInvalidation(true); + // Place the child. child->setLocation(location); // If the child moved, we have to repaint it as well as any floating/positioned // descendants. An exception is if we need a layout. In this case, we know we're going to // repaint ourselves (and the child) anyway. - if (!selfNeedsLayout() && child->checkForRepaintDuringLayout()) + if (!selfNeedsLayout() && child->checkForPaintInvalidationDuringLayout()) child->repaintDuringLayoutIfMoved(oldRect); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderDeprecatedFlexibleBox.h b/chromium/third_party/WebKit/Source/core/rendering/RenderDeprecatedFlexibleBox.h index ff039dacb2b..f6576ab2c95 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderDeprecatedFlexibleBox.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderDeprecatedFlexibleBox.h @@ -36,17 +36,17 @@ public: static RenderDeprecatedFlexibleBox* createAnonymous(Document*); - virtual const char* renderName() const; + virtual const char* renderName() const OVERRIDE; - virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle) OVERRIDE; + virtual void styleWillChange(StyleDifference, const RenderStyle& newStyle) OVERRIDE; - virtual void layoutBlock(bool relayoutChildren, LayoutUnit pageHeight = 0); + virtual void layoutBlock(bool relayoutChildren) OVERRIDE; void layoutHorizontalBox(bool relayoutChildren); void layoutVerticalBox(bool relayoutChildren); - virtual bool avoidsFloats() const { return true; } - virtual bool isDeprecatedFlexibleBox() const { return true; } - virtual bool isStretchingChildren() const { return m_stretchingChildren; } + virtual bool avoidsFloats() const OVERRIDE { return true; } + virtual bool isDeprecatedFlexibleBox() const OVERRIDE { return true; } + bool isStretchingChildren() const { return m_stretchingChildren; } virtual bool canCollapseAnonymousBlockChild() const OVERRIDE { return false; } void placeChild(RenderBox* child, const LayoutPoint& location); @@ -64,12 +64,12 @@ protected: bool m_stretchingChildren; private: - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - void applyLineClamp(FlexBoxIterator&, bool relayoutChildren); void clearLineClamp(); }; +DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderDeprecatedFlexibleBox, isDeprecatedFlexibleBox()); + } // namespace WebCore #endif // RenderDeprecatedFlexibleBox_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderDetailsMarker.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderDetailsMarker.cpp index 68e6083489c..a793c342fa4 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderDetailsMarker.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderDetailsMarker.cpp @@ -21,8 +21,9 @@ #include "config.h" #include "core/rendering/RenderDetailsMarker.h" -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/dom/Element.h" +#include "core/html/HTMLElement.h" #include "core/rendering/PaintInfo.h" #include "platform/graphics/GraphicsContext.h" @@ -106,8 +107,8 @@ Path RenderDetailsMarker::getCanonicalPath() const Path RenderDetailsMarker::getPath(const LayoutPoint& origin) const { Path result = getCanonicalPath(); - result.transform(AffineTransform().scale(contentWidth(), contentHeight())); - result.translate(FloatSize(origin.x(), origin.y())); + result.transform(AffineTransform().scale(contentWidth().toFloat(), contentHeight().toFloat())); + result.translate(FloatSize(origin.x().toFloat(), origin.y().toFloat())); return result; } @@ -121,7 +122,6 @@ void RenderDetailsMarker::paint(PaintInfo& paintInfo, const LayoutPoint& paintOf LayoutPoint boxOrigin(paintOffset + location()); LayoutRect overflowRect(visualOverflowRect()); overflowRect.moveBy(boxOrigin); - overflowRect.inflate(maximalOutlineSize(paintInfo.phase)); if (!paintInfo.rect.intersects(pixelSnappedIntRect(overflowRect))) return; @@ -141,9 +141,9 @@ bool RenderDetailsMarker::isOpen() const for (RenderObject* renderer = parent(); renderer; renderer = renderer->parent()) { if (!renderer->node()) continue; - if (renderer->node()->hasTagName(detailsTag)) + if (isHTMLDetailsElement(*renderer->node())) return !toElement(renderer->node())->getAttribute(openAttr).isNull(); - if (renderer->node()->hasTagName(inputTag)) + if (isHTMLInputElement(*renderer->node())) return true; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderDetailsMarker.h b/chromium/third_party/WebKit/Source/core/rendering/RenderDetailsMarker.h index aa996c818a2..5b20924b5bc 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderDetailsMarker.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderDetailsMarker.h @@ -34,10 +34,9 @@ public: Orientation orientation() const; private: - virtual const char* renderName() const { return "RenderDetailsMarker"; } - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - virtual bool isDetailsMarker() const { return true; } - virtual void paint(PaintInfo&, const LayoutPoint&); + virtual const char* renderName() const OVERRIDE { return "RenderDetailsMarker"; } + virtual bool isDetailsMarker() const OVERRIDE { return true; } + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; bool isOpen() const; Path getCanonicalPath() const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderEmbeddedObject.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderEmbeddedObject.cpp index 376aab5c5d8..fdd906df36b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderEmbeddedObject.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderEmbeddedObject.cpp @@ -24,14 +24,14 @@ #include "config.h" #include "core/rendering/RenderEmbeddedObject.h" -#include "CSSValueKeywords.h" -#include "HTMLNames.h" +#include "core/CSSValueKeywords.h" +#include "core/HTMLNames.h" +#include "core/frame/LocalFrame.h" #include "core/html/HTMLIFrameElement.h" -#include "core/frame/Frame.h" +#include "core/html/HTMLPlugInElement.h" #include "core/page/Page.h" #include "core/frame/Settings.h" #include "core/plugins/PluginView.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/PaintInfo.h" #include "core/rendering/RenderTheme.h" #include "core/rendering/RenderView.h" @@ -54,7 +54,6 @@ static const float replacementTextTextOpacity = 0.55f; RenderEmbeddedObject::RenderEmbeddedObject(Element* element) : RenderPart(element) - , m_hasFallbackContent(false) , m_showsUnavailablePluginIndicator(false) { view()->frameView()->setIsVisuallyNonEmpty(); @@ -64,17 +63,16 @@ RenderEmbeddedObject::~RenderEmbeddedObject() { } -bool RenderEmbeddedObject::requiresLayer() const +LayerType RenderEmbeddedObject::layerTypeRequired() const { - if (RenderPart::requiresLayer()) - return true; - - return allowsAcceleratedCompositing(); -} - -bool RenderEmbeddedObject::allowsAcceleratedCompositing() const -{ - return widget() && widget()->isPluginView() && toPluginView(widget())->platformLayer(); + // This can't just use RenderPart::layerTypeRequired, because RenderLayerCompositor + // doesn't loop through RenderEmbeddedObjects the way it does frames in order + // to update the self painting bit on their RenderLayer. + // Also, unlike iframes, embeds don't used the usesCompositing bit on RenderView + // in requiresAcceleratedCompositing. + if (requiresAcceleratedCompositing()) + return NormalLayer; + return RenderPart::layerTypeRequired(); } static String unavailablePluginReplacementText(Node* node, RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) @@ -108,7 +106,7 @@ bool RenderEmbeddedObject::showsUnavailablePluginIndicator() const void RenderEmbeddedObject::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { Element* element = toElement(node()); - if (!element || !element->isPluginElement()) + if (!isHTMLPlugInElement(element)) return; RenderPart::paintContents(paintInfo, paintOffset); @@ -147,7 +145,7 @@ void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, const LayoutPoint GraphicsContextStateSaver stateSaver(*context); context->clip(contentRect); - context->setAlpha(replacementTextRoundedRectOpacity); + context->setAlphaAsFloat(replacementTextRoundedRectOpacity); context->setFillColor(Color::white); context->fillPath(path); @@ -156,7 +154,7 @@ void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, const LayoutPoint float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - fontMetrics.height()) / 2 + fontMetrics.ascent()); TextRunPaintInfo runInfo(run); runInfo.bounds = replacementTextRect; - context->setAlpha(replacementTextTextOpacity); + context->setAlphaAsFloat(replacementTextTextOpacity); context->setFillColor(Color::black); context->drawBidiText(font, runInfo, FloatPoint(labelX, labelY)); } @@ -174,8 +172,8 @@ bool RenderEmbeddedObject::getReplacementTextGeometry(const LayoutPoint& accumul if (!settings) return false; fontDescription.setComputedSize(fontDescription.specifiedSize()); - font = Font(fontDescription, 0, 0); - font.update(0); + font = Font(fontDescription); + font.update(nullptr); run = TextRun(m_unavailablePluginReplacementText); textWidth = font.width(run); @@ -194,83 +192,37 @@ void RenderEmbeddedObject::layout() { ASSERT(needsLayout()); - LayoutSize oldSize = contentBoxRect().size(); - LayoutRectRecorder recorder(*this); - updateLogicalWidth(); updateLogicalHeight(); - RenderPart::layout(); - m_overflow.clear(); addVisualEffectOverflow(); - updateLayerTransform(); + updateLayerTransformAfterLayout(); if (!widget() && frameView()) frameView()->addWidgetToUpdate(*this); clearNeedsLayout(); - - if (!canHaveChildren()) - return; - - // This code copied from RenderMedia::layout(). - RenderObject* child = m_children.firstChild(); - - if (!child) - return; - - RenderBox* childBox = toRenderBox(child); - - if (!childBox) - return; - - LayoutSize newSize = contentBoxRect().size(); - if (newSize == oldSize && !childBox->needsLayout()) - return; - - // When calling layout() on a child node, a parent must either push a LayoutStateMaintainter, or - // instantiate LayoutStateDisabler. Since using a LayoutStateMaintainer is slightly more efficient, - // and this method will be called many times per second during playback, use a LayoutStateMaintainer: - LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode()); - - childBox->setLocation(LayoutPoint(borderLeft(), borderTop()) + LayoutSize(paddingLeft(), paddingTop())); - childBox->style()->setHeight(Length(newSize.height(), Fixed)); - childBox->style()->setWidth(Length(newSize.width(), Fixed)); - childBox->forceLayout(); - clearNeedsLayout(); - - statePusher.pop(); } -void RenderEmbeddedObject::viewCleared() +bool RenderEmbeddedObject::scroll(ScrollDirection direction, ScrollGranularity granularity, float) { - // This is required for <object> elements whose contents are rendered by WebCore (e.g. src="foo.html"). - if (node() && widget() && widget()->isFrameView()) { - FrameView* view = toFrameView(widget()); - int marginWidth = -1; - int marginHeight = -1; - if (node()->hasTagName(iframeTag)) { - HTMLIFrameElement* frame = toHTMLIFrameElement(node()); - marginWidth = frame->marginWidth(); - marginHeight = frame->marginHeight(); - } - if (marginWidth != -1) - view->setMarginWidth(marginWidth); - if (marginHeight != -1) - view->setMarginHeight(marginHeight); - } + return false; } -bool RenderEmbeddedObject::scroll(ScrollDirection direction, ScrollGranularity granularity, float) +CompositingReasons RenderEmbeddedObject::additionalCompositingReasons(CompositingTriggerFlags triggers) const { - return false; + if (requiresAcceleratedCompositing()) + return CompositingReasonPlugin; + return CompositingReasonNone; } -bool RenderEmbeddedObject::canHaveChildren() const +RenderBox* RenderEmbeddedObject::embeddedContentBox() const { - return false; + if (!node() || !widget() || !widget()->isFrameView()) + return 0; + return toFrameView(widget())->embeddedContentBox(); } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderEmbeddedObject.h b/chromium/third_party/WebKit/Source/core/rendering/RenderEmbeddedObject.h index 679658ec445..a33e28300b9 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderEmbeddedObject.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderEmbeddedObject.h @@ -27,7 +27,6 @@ namespace WebCore { -class MouseEvent; class TextRun; // Renderer for embeds and objects, often, but not always, rendered via plug-ins. @@ -44,47 +43,32 @@ public: void setPluginUnavailabilityReason(PluginUnavailabilityReason); bool showsUnavailablePluginIndicator() const; - // FIXME: This belongs on HTMLObjectElement. - bool hasFallbackContent() const { return m_hasFallbackContent; } - void setHasFallbackContent(bool hasFallbackContent) { m_hasFallbackContent = hasFallbackContent; } - - bool allowsAcceleratedCompositing() const; - protected: virtual void paintReplaced(PaintInfo&, const LayoutPoint&) OVERRIDE FINAL; virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE FINAL; - const RenderObjectChildList* children() const { return &m_children; } - RenderObjectChildList* children() { return &m_children; } - protected: virtual void layout() OVERRIDE FINAL; private: - virtual const char* renderName() const { return "RenderEmbeddedObject"; } + virtual const char* renderName() const OVERRIDE { return "RenderEmbeddedObject"; } virtual bool isEmbeddedObject() const OVERRIDE FINAL { return true; } + virtual RenderBox* embeddedContentBox() const OVERRIDE FINAL; void paintSnapshotImage(PaintInfo&, const LayoutPoint&, Image*); virtual void paintContents(PaintInfo&, const LayoutPoint&) OVERRIDE FINAL; - virtual bool requiresLayer() const OVERRIDE FINAL; - - virtual void viewCleared() OVERRIDE FINAL; + virtual LayerType layerTypeRequired() const OVERRIDE FINAL; virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier) OVERRIDE FINAL; bool getReplacementTextGeometry(const LayoutPoint& accumulatedOffset, FloatRect& contentRect, Path&, FloatRect& replacementTextRect, Font&, TextRun&, float& textWidth) const; - virtual bool canHaveChildren() const OVERRIDE FINAL; - virtual RenderObjectChildList* virtualChildren() OVERRIDE FINAL { return children(); } - virtual const RenderObjectChildList* virtualChildren() const OVERRIDE FINAL { return children(); } - - bool m_hasFallbackContent; // FIXME: This belongs on HTMLObjectElement. + virtual CompositingReasons additionalCompositingReasons(CompositingTriggerFlags) const OVERRIDE; bool m_showsUnavailablePluginIndicator; PluginUnavailabilityReason m_pluginUnavailabilityReason; String m_unavailablePluginReplacementText; - RenderObjectChildList m_children; }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderEmbeddedObject, isEmbeddedObject()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderFieldset.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderFieldset.cpp index b3962cf6f0a..bf1de947644 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderFieldset.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderFieldset.cpp @@ -24,8 +24,9 @@ #include "config.h" #include "core/rendering/RenderFieldset.h" -#include "CSSPropertyNames.h" -#include "HTMLNames.h" +#include "core/CSSPropertyNames.h" +#include "core/HTMLNames.h" +#include "core/html/HTMLLegendElement.h" #include "core/rendering/PaintInfo.h" #include "platform/graphics/GraphicsContextStateSaver.h" @@ -43,7 +44,7 @@ RenderFieldset::RenderFieldset(Element* element) void RenderFieldset::computePreferredLogicalWidths() { - RenderBlock::computePreferredLogicalWidths(); + RenderBlockFlow::computePreferredLogicalWidths(); if (RenderBox* legend = findLegend()) { int legendMinWidth = legend->minPreferredLogicalWidth(); @@ -65,7 +66,7 @@ RenderObject* RenderFieldset::layoutSpecialExcludedChild(bool relayoutChildren, RenderBox* legend = findLegend(); if (legend) { if (relayoutChildren) - legend->setNeedsLayout(); + legend->setNeedsLayoutAndFullPaintInvalidation(); legend->layoutIfNeeded(); LayoutUnit logicalLeft; @@ -129,7 +130,7 @@ RenderBox* RenderFieldset::findLegend(FindLegendOption option) const if (option == IgnoreFloatingOrOutOfFlow && legend->isFloatingOrOutOfFlowPositioned()) continue; - if (legend->node() && (legend->node()->hasTagName(legendTag))) + if (isHTMLLegendElement(legend->node())) return toRenderBox(legend); } return 0; @@ -143,7 +144,7 @@ void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint LayoutRect paintRect(paintOffset, size()); RenderBox* legend = findLegend(); if (!legend) - return RenderBlock::paintBoxDecorations(paintInfo, paintOffset); + return RenderBlockFlow::paintBoxDecorations(paintInfo, paintOffset); // FIXME: We need to work with "rl" and "bt" block flow directions. In those // cases the legend is embedded in the right and bottom borders respectively. @@ -194,7 +195,7 @@ void RenderFieldset::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOff LayoutRect paintRect = LayoutRect(paintOffset, size()); RenderBox* legend = findLegend(); if (!legend) - return RenderBlock::paintMask(paintInfo, paintOffset); + return RenderBlockFlow::paintMask(paintInfo, paintOffset); // FIXME: We need to work with "rl" and "bt" block flow directions. In those // cases the legend is embedded in the right and bottom borders respectively. diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderFieldset.h b/chromium/third_party/WebKit/Source/core/rendering/RenderFieldset.h index 944ab4c1dc6..0ebc486eca2 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderFieldset.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderFieldset.h @@ -36,18 +36,16 @@ public: RenderBox* findLegend(FindLegendOption = IgnoreFloatingOrOutOfFlow) const; private: - virtual const char* renderName() const { return "RenderFieldSet"; } - virtual bool isFieldset() const { return true; } + virtual const char* renderName() const OVERRIDE { return "RenderFieldSet"; } + virtual bool isFieldset() const OVERRIDE { return true; } - virtual RenderObject* layoutSpecialExcludedChild(bool relayoutChildren, SubtreeLayoutScope&); + virtual RenderObject* layoutSpecialExcludedChild(bool relayoutChildren, SubtreeLayoutScope&) OVERRIDE; - virtual void computePreferredLogicalWidths(); - virtual bool avoidsFloats() const { return true; } + virtual void computePreferredLogicalWidths() OVERRIDE; + virtual bool avoidsFloats() const OVERRIDE { return true; } - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - - virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&); - virtual void paintMask(PaintInfo&, const LayoutPoint&); + virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&) OVERRIDE; + virtual void paintMask(PaintInfo&, const LayoutPoint&) OVERRIDE; }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderFieldset, isFieldset()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderFileUploadControl.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderFileUploadControl.cpp index 80a822fe74c..9fd7784719c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderFileUploadControl.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderFileUploadControl.cpp @@ -21,8 +21,7 @@ #include "config.h" #include "core/rendering/RenderFileUploadControl.h" -#include <math.h> -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/dom/shadow/ElementShadow.h" #include "core/dom/shadow/ShadowRoot.h" #include "core/fileapi/FileList.h" @@ -34,6 +33,7 @@ #include "platform/graphics/GraphicsContextStateSaver.h" #include "platform/text/PlatformLocale.h" #include "platform/text/TextRun.h" +#include <math.h> using namespace std; @@ -73,7 +73,7 @@ void RenderFileUploadControl::updateFromElement() FileList* files = input->files(); ASSERT(files); if (files && files->isEmpty()) - repaint(); + paintInvalidationForWholeRenderer(); } static int nodeWidth(Node* node) @@ -131,10 +131,9 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, const LayoutPoin else textY = baselinePosition(AlphabeticBaseline, true, HorizontalLine, PositionOnContainingLine); TextRunPaintInfo textRunPaintInfo(textRun); - textRunPaintInfo.bounds = FloatRect(textX, - textY - style()->fontMetrics().ascent(), - textWidth, - style()->fontMetrics().height()); + // FIXME: Shouldn't these offsets be rounded? crbug.com/350474 + textRunPaintInfo.bounds = FloatRect(textX.toFloat(), textY.toFloat() - style()->fontMetrics().ascent(), + textWidth, style()->fontMetrics().height()); paintInfo.context->setFillColor(resolveColor(CSSPropertyColor)); @@ -143,7 +142,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, const LayoutPoin } // Paint the children. - RenderBlock::paintObject(paintInfo, paintOffset); + RenderBlockFlow::paintObject(paintInfo, paintOffset); } void RenderFileUploadControl::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const @@ -174,20 +173,21 @@ void RenderFileUploadControl::computePreferredLogicalWidths() m_minPreferredLogicalWidth = 0; m_maxPreferredLogicalWidth = 0; + RenderStyle* styleToUse = style(); - if (style()->width().isFixed() && style()->width().value() > 0) - m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->width().value()); + if (styleToUse->width().isFixed() && styleToUse->width().value() > 0) + m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->width().value()); else computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth); - if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) { - m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value())); - m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value())); + if (styleToUse->minWidth().isFixed() && styleToUse->minWidth().value() > 0) { + m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->minWidth().value())); + m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->minWidth().value())); } - if (style()->maxWidth().isFixed()) { - m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value())); - m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value())); + if (styleToUse->maxWidth().isFixed()) { + m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->maxWidth().value())); + m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->maxWidth().value())); } int toAdd = borderAndPaddingWidth(); @@ -207,7 +207,7 @@ HTMLInputElement* RenderFileUploadControl::uploadButton() const // FIXME: This should be on HTMLInputElement as an API like innerButtonElement(). HTMLInputElement* input = toHTMLInputElement(node()); Node* buttonNode = input->userAgentShadowRoot()->firstChild(); - return buttonNode && buttonNode->isHTMLElement() && buttonNode->hasTagName(inputTag) ? toHTMLInputElement(buttonNode) : 0; + return isHTMLInputElement(buttonNode) ? toHTMLInputElement(buttonNode) : 0; } String RenderFileUploadControl::buttonValue() diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderFileUploadControl.h b/chromium/third_party/WebKit/Source/core/rendering/RenderFileUploadControl.h index f83bb2a585d..5e2f70410a2 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderFileUploadControl.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderFileUploadControl.h @@ -36,24 +36,22 @@ public: RenderFileUploadControl(HTMLInputElement*); virtual ~RenderFileUploadControl(); - virtual bool isFileUploadControl() const { return true; } + virtual bool isFileUploadControl() const OVERRIDE { return true; } String buttonValue(); String fileTextValue() const; private: - virtual const char* renderName() const { return "RenderFileUploadControl"; } + virtual const char* renderName() const OVERRIDE { return "RenderFileUploadControl"; } - virtual void updateFromElement(); + virtual void updateFromElement() OVERRIDE; virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE; - virtual void computePreferredLogicalWidths(); - virtual void paintObject(PaintInfo&, const LayoutPoint&); - - virtual bool supportsPartialLayout() const OVERRIDE { return false; } + virtual void computePreferredLogicalWidths() OVERRIDE; + virtual void paintObject(PaintInfo&, const LayoutPoint&) OVERRIDE; int maxFilenameWidth() const; - virtual PositionWithAffinity positionForPoint(const LayoutPoint&) OVERRIDE FINAL; + virtual PositionWithAffinity positionForPoint(const LayoutPoint&) OVERRIDE; HTMLInputElement* uploadButton() const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderFlexibleBox.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderFlexibleBox.cpp index 65c82221b62..6114d5654cd 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderFlexibleBox.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderFlexibleBox.cpp @@ -31,11 +31,13 @@ #include "config.h" #include "core/rendering/RenderFlexibleBox.h" -#include <limits> +#include "core/rendering/FastTextAutosizer.h" #include "core/rendering/LayoutRepainter.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderView.h" +#include "platform/LengthFunctions.h" #include "wtf/MathExtras.h" +#include <limits> namespace WebCore { @@ -141,8 +143,7 @@ int RenderFlexibleBox::baselinePosition(FontBaseline, bool, LineDirectionMode di if (baseline == -1) baseline = synthesizedBaselineFromContentBox(this, direction); - int marginAscent = direction == HorizontalLine ? marginTop() : marginRight(); - return baseline + marginAscent; + return beforeMarginInLineDirection(direction) + baseline; } int RenderFlexibleBox::firstLineBoxBaseline() const @@ -154,7 +155,7 @@ int RenderFlexibleBox::firstLineBoxBaseline() const for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) { if (child->isOutOfFlowPositioned()) continue; - if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child)) { + if (alignmentForChild(child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(child)) { baselineChild = child; break; } @@ -195,37 +196,43 @@ int RenderFlexibleBox::inlineBlockBaseline(LineDirectionMode direction) const return synthesizedBaselineFromContentBox(this, direction) + marginAscent; } -static EAlignItems resolveAlignment(const RenderStyle* parentStyle, const RenderStyle* childStyle) +static ItemPosition resolveAlignment(const RenderStyle* parentStyle, const RenderStyle* childStyle) { - EAlignItems align = childStyle->alignSelf(); - if (align == AlignAuto) + ItemPosition align = childStyle->alignSelf(); + if (align == ItemPositionAuto) align = parentStyle->alignItems(); return align; } +void RenderFlexibleBox::removeChild(RenderObject* child) +{ + RenderBlock::removeChild(child); + m_intrinsicSizeAlongMainAxis.remove(child); +} + void RenderFlexibleBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); - if (oldStyle && oldStyle->alignItems() == AlignStretch && diff == StyleDifferenceLayout) { + if (oldStyle && oldStyle->alignItems() == ItemPositionStretch && diff.needsFullLayout()) { // Flex items that were previously stretching need to be relayed out so we can compute new available cross axis space. // This is only necessary for stretching since other alignment values don't change the size of the box. for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { - EAlignItems previousAlignment = resolveAlignment(oldStyle, child->style()); - if (previousAlignment == AlignStretch && previousAlignment != resolveAlignment(style(), child->style())) + ItemPosition previousAlignment = resolveAlignment(oldStyle, child->style()); + if (previousAlignment == ItemPositionStretch && previousAlignment != resolveAlignment(style(), child->style())) child->setChildNeedsLayout(MarkOnlyThis); } } } -void RenderFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit) +void RenderFlexibleBox::layoutBlock(bool relayoutChildren) { ASSERT(needsLayout()); if (!relayoutChildren && simplifiedLayout()) return; - LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); + LayoutRepainter repainter(*this, checkForPaintInvalidationDuringLayout()); if (updateLogicalWidthAndColumnWidth()) relayoutChildren = true; @@ -233,45 +240,36 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit) LayoutUnit previousHeight = logicalHeight(); setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight()); - LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode()); - - // Regions changing widths can force us to relayout our children. - RenderFlowThread* flowThread = flowThreadContainingBlock(); - if (logicalWidthChangedInRegions(flowThread)) - relayoutChildren = true; - if (updateRegionsAndShapesLogicalSize(flowThread)) - relayoutChildren = true; - - m_numberOfInFlowChildrenOnFirstLine = -1; + { + FastTextAutosizer::LayoutScope fastTextAutosizerLayoutScope(this); + LayoutState state(*this, locationOffset()); - RenderBlock::startDelayUpdateScrollInfo(); + m_numberOfInFlowChildrenOnFirstLine = -1; - prepareOrderIteratorAndMargins(); + RenderBlock::startDelayUpdateScrollInfo(); - ChildFrameRects oldChildRects; - appendChildFrameRects(oldChildRects); + prepareOrderIteratorAndMargins(); - Vector<LineContext> lineContexts; - layoutFlexItems(relayoutChildren, lineContexts); + ChildFrameRects oldChildRects; + appendChildFrameRects(oldChildRects); - updateLogicalHeight(); - repositionLogicalHeightDependentFlexItems(lineContexts); + layoutFlexItems(relayoutChildren); - RenderBlock::finishDelayUpdateScrollInfo(); + RenderBlock::finishDelayUpdateScrollInfo(); - if (logicalHeight() != previousHeight) - relayoutChildren = true; + if (logicalHeight() != previousHeight) + relayoutChildren = true; - layoutPositionedObjects(relayoutChildren || isRoot()); + layoutPositionedObjects(relayoutChildren || isDocumentElement()); - computeRegionRangeForBlock(flowThread); + computeRegionRangeForBlock(flowThreadContainingBlock()); - repaintChildrenDuringLayoutIfMoved(oldChildRects); - // FIXME: css3/flexbox/repaint-rtl-column.html seems to repaint more overflow than it needs to. - computeOverflow(clientLogicalBottomAfterRepositioning()); - statePusher.pop(); + repaintChildrenDuringLayoutIfMoved(oldChildRects); + // FIXME: css3/flexbox/repaint-rtl-column.html seems to repaint more overflow than it needs to. + computeOverflow(clientLogicalBottomAfterRepositioning()); + } - updateLayerTransform(); + updateLayerTransformAfterLayout(); // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if // we overflow or not. @@ -300,7 +298,7 @@ void RenderFlexibleBox::repaintChildrenDuringLayoutIfMoved(const ChildFrameRects // If the child moved, we have to repaint it as well as any floating/positioned // descendants. An exception is if we need a layout. In this case, we know we're going to // repaint ourselves (and the child) anyway. - if (!selfNeedsLayout() && child->checkForRepaintDuringLayout()) + if (!selfNeedsLayout() && child->checkForPaintInvalidationDuringLayout()) child->repaintDuringLayoutIfMoved(oldChildRects[childIndex]); ++childIndex; } @@ -318,10 +316,6 @@ void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(Vector<LineCon LayoutUnit crossAxisStartEdge = lineContexts.isEmpty() ? LayoutUnit() : lineContexts[0].crossAxisOffset; alignFlexLines(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 updateLogicalHeight. - if (!isMultiline() && lineContexts.size() == 1) - lineContexts[0].crossAxisExtent = crossAxisContentExtent(); alignChildren(lineContexts); if (style()->flexWrap() == FlexWrapReverse) @@ -340,7 +334,7 @@ LayoutUnit RenderFlexibleBox::clientLogicalBottomAfterRepositioning() LayoutUnit childLogicalBottom = logicalTopForChild(child) + logicalHeightForChild(child) + marginAfterForChild(child); maxChildLogicalBottom = std::max(maxChildLogicalBottom, childLogicalBottom); } - return std::max(clientLogicalBottom(), maxChildLogicalBottom); + return std::max(clientLogicalBottom(), maxChildLogicalBottom + paddingAfter()); } bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox* child) const @@ -381,17 +375,34 @@ Length RenderFlexibleBox::flexBasisForChild(RenderBox* child) const return flexLength; } -void RenderFlexibleBox::setCrossAxisExtent(LayoutUnit extent) +LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(RenderBox* child) const { - if (isHorizontalFlow()) - setHeight(extent); - else - setWidth(extent); + return isHorizontalFlow() ? child->height() : child->width(); } -LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(RenderBox* child) const +static inline LayoutUnit constrainedChildIntrinsicContentLogicalHeight(RenderBox* child) { - return isHorizontalFlow() ? child->height() : child->width(); + LayoutUnit childIntrinsicContentLogicalHeight = child->intrinsicContentLogicalHeight(); + return child->constrainLogicalHeightByMinMax(childIntrinsicContentLogicalHeight + child->borderAndPaddingLogicalHeight(), childIntrinsicContentLogicalHeight); +} + +LayoutUnit RenderFlexibleBox::childIntrinsicHeight(RenderBox* child) const +{ + if (child->isHorizontalWritingMode() && needToStretchChildLogicalHeight(child)) + return constrainedChildIntrinsicContentLogicalHeight(child); + return child->height(); +} + +LayoutUnit RenderFlexibleBox::childIntrinsicWidth(RenderBox* child) const +{ + if (!child->isHorizontalWritingMode() && needToStretchChildLogicalHeight(child)) + return constrainedChildIntrinsicContentLogicalHeight(child); + return child->width(); +} + +LayoutUnit RenderFlexibleBox::crossAxisIntrinsicExtentForChild(RenderBox* child) const +{ + return isHorizontalFlow() ? childIntrinsicHeight(child) : childIntrinsicWidth(child); } LayoutUnit RenderFlexibleBox::mainAxisExtentForChild(RenderBox* child) const @@ -439,9 +450,7 @@ LayoutUnit RenderFlexibleBox::computeMainAxisExtentForChild(RenderBox* child, Si child->layoutIfNeeded(); return child->computeContentLogicalHeight(size, child->logicalHeight() - child->borderAndPaddingLogicalHeight()); } - // FIXME: Figure out how this should work for regions and pass in the appropriate values. - RenderRegion* region = 0; - return child->computeLogicalWidthInRegionUsing(sizeType, size, contentLogicalWidth(), this, region) - child->borderAndPaddingLogicalWidth(); + return child->computeLogicalWidthUsing(sizeType, size, contentLogicalWidth(), this) - child->borderAndPaddingLogicalWidth(); } WritingMode RenderFlexibleBox::transformedWritingMode() const @@ -584,22 +593,6 @@ LayoutUnit RenderFlexibleBox::flowAwareMarginBeforeForChild(RenderBox* child) co return marginTop(); } -LayoutUnit RenderFlexibleBox::flowAwareMarginAfterForChild(RenderBox* child) const -{ - switch (transformedWritingMode()) { - case TopToBottomWritingMode: - return child->marginBottom(); - case BottomToTopWritingMode: - return child->marginTop(); - case LeftToRightWritingMode: - return child->marginRight(); - case RightToLeftWritingMode: - return child->marginLeft(); - } - ASSERT_NOT_REACHED(); - return marginBottom(); -} - LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(RenderBox* child) const { return isHorizontalFlow() ? child->marginHeight() : child->marginWidth(); @@ -628,54 +621,66 @@ LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox* return isHorizontalFlow() ? child->borderAndPaddingWidth() : child->borderAndPaddingHeight(); } -LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox* child) const +static inline bool preferredMainAxisExtentDependsOnLayout(const Length& flexBasis, bool hasInfiniteLineLength) +{ + return flexBasis.isAuto() || (flexBasis.isFixed() && !flexBasis.value() && hasInfiniteLineLength); +} + +bool RenderFlexibleBox::childPreferredMainAxisContentExtentRequiresLayout(RenderBox* child, bool hasInfiniteLineLength) const { - return isHorizontalFlow() ? child->verticalScrollbarWidth() : child->horizontalScrollbarHeight(); + return preferredMainAxisExtentDependsOnLayout(flexBasisForChild(child), hasInfiniteLineLength) && hasOrthogonalFlow(child); } -LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child, bool hasInfiniteLineLength) +LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child, bool hasInfiniteLineLength, bool relayoutChildren) { - bool hasOverrideSize = child->hasOverrideWidth() || child->hasOverrideHeight(); - if (hasOverrideSize) - child->clearOverrideSize(); + child->clearOverrideSize(); Length flexBasis = flexBasisForChild(child); - if (flexBasis.isAuto() || (flexBasis.isFixed() && !flexBasis.value() && hasInfiniteLineLength)) { + if (preferredMainAxisExtentDependsOnLayout(flexBasis, hasInfiniteLineLength)) { + LayoutUnit mainAxisExtent; if (hasOrthogonalFlow(child)) { - if (hasOverrideSize) - child->setChildNeedsLayout(MarkOnlyThis); - child->layoutIfNeeded(); + if (child->needsLayout() || relayoutChildren) { + m_intrinsicSizeAlongMainAxis.remove(child); + child->forceChildLayout(); + m_intrinsicSizeAlongMainAxis.set(child, child->logicalHeight()); + } + ASSERT(m_intrinsicSizeAlongMainAxis.contains(child)); + mainAxisExtent = m_intrinsicSizeAlongMainAxis.get(child); + } else { + mainAxisExtent = child->maxPreferredLogicalWidth(); } - LayoutUnit mainAxisExtent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->maxPreferredLogicalWidth(); ASSERT(mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child) >= 0); return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child); } return std::max(LayoutUnit(0), computeMainAxisExtentForChild(child, MainOrPreferredSize, flexBasis)); } -void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren, Vector<LineContext>& lineContexts) +void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren) { + Vector<LineContext> lineContexts; OrderedFlexItemList orderedChildren; LayoutUnit sumFlexBaseSize; double totalFlexGrow; double totalWeightedFlexShrink; LayoutUnit sumHypotheticalMainSize; + Vector<LayoutUnit, 16> childSizes; + m_orderIterator.first(); LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore(); bool hasInfiniteLineLength = false; - while (computeNextFlexLine(orderedChildren, sumFlexBaseSize, totalFlexGrow, totalWeightedFlexShrink, sumHypotheticalMainSize, hasInfiniteLineLength)) { + while (computeNextFlexLine(orderedChildren, sumFlexBaseSize, totalFlexGrow, totalWeightedFlexShrink, sumHypotheticalMainSize, hasInfiniteLineLength, relayoutChildren)) { LayoutUnit containerMainInnerSize = mainAxisContentExtent(sumHypotheticalMainSize); LayoutUnit availableFreeSpace = containerMainInnerSize - sumFlexBaseSize; FlexSign flexSign = (sumHypotheticalMainSize < containerMainInnerSize) ? PositiveFlexibility : NegativeFlexibility; InflexibleFlexItemSize inflexibleItems; - Vector<LayoutUnit> childSizes; + childSizes.reserveCapacity(orderedChildren.size()); while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes, hasInfiniteLineLength)) { ASSERT(totalFlexGrow >= 0 && totalWeightedFlexShrink >= 0); ASSERT(inflexibleItems.size() > 0); } - layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, relayoutChildren, lineContexts); + layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, relayoutChildren, lineContexts, hasInfiniteLineLength); } if (hasLineIfEmpty()) { // Even if computeNextFlexLine returns true, the flexbox might not have @@ -688,6 +693,9 @@ void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren, Vector<LineContex if (height() < minHeight) setLogicalHeight(minHeight); } + + updateLogicalHeight(); + repositionLogicalHeightDependentFlexItems(lineContexts); } LayoutUnit RenderFlexibleBox::autoMarginOffsetInMainAxis(const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace) @@ -752,6 +760,13 @@ LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCro return lineCrossAxisExtent - childCrossExtent; } +LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChildBeforeStretching(LayoutUnit lineCrossAxisExtent, RenderBox* child) +{ + ASSERT(!child->isOutOfFlowPositioned()); + LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisIntrinsicExtentForChild(child); + return lineCrossAxisExtent - childCrossExtent; +} + bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox* child, LayoutUnit availableAlignmentSpace) { ASSERT(!child->isOutOfFlowPositioned()); @@ -814,17 +829,16 @@ LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox* child) return ascent + flowAwareMarginBeforeForChild(child); } -LayoutUnit RenderFlexibleBox::computeChildMarginValue(Length margin, RenderView* view) +LayoutUnit RenderFlexibleBox::computeChildMarginValue(Length margin) { // When resolving the margins, we use the content size for resolving percent and calc (for percents in calc expressions) margins. // Fortunately, percent margins are always computed with respect to the block's width, even for margin-top and margin-bottom. LayoutUnit availableSize = contentLogicalWidth(); - return minimumValueForLength(margin, availableSize, view); + return minimumValueForLength(margin, availableSize); } void RenderFlexibleBox::prepareOrderIteratorAndMargins() { - RenderView* renderView = view(); OrderIteratorPopulator populator(m_orderIterator); for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { @@ -836,11 +850,11 @@ void RenderFlexibleBox::prepareOrderIteratorAndMargins() // Before running the flex algorithm, 'auto' has a margin of 0. // Also, if we're not auto sizing, we don't do a layout that computes the start/end margins. if (isHorizontalFlow()) { - child->setMarginLeft(computeChildMarginValue(child->style()->marginLeft(), renderView)); - child->setMarginRight(computeChildMarginValue(child->style()->marginRight(), renderView)); + child->setMarginLeft(computeChildMarginValue(child->style()->marginLeft())); + child->setMarginRight(computeChildMarginValue(child->style()->marginRight())); } else { - child->setMarginTop(computeChildMarginValue(child->style()->marginTop(), renderView)); - child->setMarginBottom(computeChildMarginValue(child->style()->marginBottom(), renderView)); + child->setMarginTop(computeChildMarginValue(child->style()->marginTop())); + child->setMarginBottom(computeChildMarginValue(child->style()->marginBottom())); } } } @@ -861,7 +875,7 @@ LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox* child, Layo return std::max(childSize, minExtent); } -bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& sumFlexBaseSize, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& sumHypotheticalMainSize, bool& hasInfiniteLineLength) +bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& sumFlexBaseSize, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& sumHypotheticalMainSize, bool& hasInfiniteLineLength, bool relayoutChildren) { orderedChildren.clear(); sumFlexBaseSize = 0; @@ -882,7 +896,7 @@ bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren continue; } - LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength); + LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength, relayoutChildren); LayoutUnit childMainAxisMarginBorderPadding = mainAxisBorderAndPaddingExtentForChild(child) + (isHorizontalFlow() ? child->marginWidth() : child->marginHeight()); LayoutUnit childFlexBaseSize = childMainAxisExtent + childMainAxisMarginBorderPadding; @@ -916,9 +930,9 @@ void RenderFlexibleBox::freezeViolations(const Vector<Violation>& violations, La } // Returns true if we successfully ran the algorithm and sized the flex items. -bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, Vector<LayoutUnit>& childSizes, bool hasInfiniteLineLength) +bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, Vector<LayoutUnit, 16>& childSizes, bool hasInfiniteLineLength) { - childSizes.clear(); + childSizes.resize(0); LayoutUnit totalViolation = 0; LayoutUnit usedFreeSpace = 0; Vector<Violation> minViolations; @@ -1006,7 +1020,7 @@ void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox* child, Layout LayoutUnit inlinePosition = isColumnFlow() ? crossAxisOffset : mainAxisOffset; if (layoutMode == FlipForRowReverse && style()->flexDirection() == FlowRowReverse) inlinePosition = mainAxisExtent() - mainAxisOffset; - childLayer->setStaticInlinePosition(inlinePosition); // FIXME: Not right for regions. + childLayer->setStaticInlinePosition(inlinePosition); LayoutUnit staticBlockPosition = isColumnFlow() ? mainAxisOffset : crossAxisOffset; if (childLayer->staticBlockPosition() != staticBlockPosition) { @@ -1016,18 +1030,18 @@ void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox* child, Layout } } -EAlignItems RenderFlexibleBox::alignmentForChild(RenderBox* child) const +ItemPosition RenderFlexibleBox::alignmentForChild(RenderBox* child) const { - EAlignItems align = resolveAlignment(style(), child->style()); + ItemPosition align = resolveAlignment(style(), child->style()); - if (align == AlignBaseline && hasOrthogonalFlow(child)) - align = AlignFlexStart; + if (align == ItemPositionBaseline && hasOrthogonalFlow(child)) + align = ItemPositionFlexStart; if (style()->flexWrap() == FlexWrapReverse) { - if (align == AlignFlexStart) - align = AlignFlexEnd; - else if (align == AlignFlexEnd) - align = AlignFlexStart; + if (align == ItemPositionFlexStart) + align = ItemPositionFlexEnd; + else if (align == ItemPositionFlexEnd) + align = ItemPositionFlexStart; } return align; @@ -1044,22 +1058,33 @@ size_t RenderFlexibleBox::numberOfInFlowPositionedChildren(const OrderedFlexItem return count; } -bool RenderFlexibleBox::needToStretchChild(RenderBox* child) +void RenderFlexibleBox::resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox* child) { - if (alignmentForChild(child) != AlignStretch) - return false; - - Length crossAxisLength = isHorizontalFlow() ? child->style()->height() : child->style()->width(); - return crossAxisLength.isAuto(); + if (hasAutoMarginsInCrossAxis(child)) { + child->updateLogicalHeight(); + if (isHorizontalFlow()) { + if (child->style()->marginTop().isAuto()) + child->setMarginTop(0); + if (child->style()->marginBottom().isAuto()) + child->setMarginBottom(0); + } else { + if (child->style()->marginLeft().isAuto()) + child->setMarginLeft(0); + if (child->style()->marginRight().isAuto()) + child->setMarginRight(0); + } + } } -void RenderFlexibleBox::resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox* child) +bool RenderFlexibleBox::needToStretchChildLogicalHeight(RenderBox* child) const { - if (hasAutoMarginsInCrossAxis(child)) - child->updateLogicalHeight(); + if (alignmentForChild(child) != ItemPositionStretch) + return false; + + return isHorizontalFlow() && child->style()->height().isAuto(); } -void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>& lineContexts) +void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const Vector<LayoutUnit, 16>& childSizes, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>& lineContexts, bool hasInfiniteLineLength) { ASSERT(childSizes.size() == children.size()); @@ -1077,27 +1102,32 @@ void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, cons bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow(); for (size_t i = 0; i < children.size(); ++i) { RenderBox* child = children[i]; + if (child->isOutOfFlowPositioned()) { prepareChildForPositionedLayout(child, mainAxisOffset, crossAxisOffset, FlipForRowReverse); continue; } + // FIXME Investigate if this can be removed based on other flags. crbug.com/370010 + child->setMayNeedPaintInvalidation(true); + LayoutUnit childPreferredSize = childSizes[i] + mainAxisBorderAndPaddingExtentForChild(child); setLogicalOverrideSize(child, childPreferredSize); - // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905. - if (needToStretchChild(child) || childPreferredSize != mainAxisExtentForChild(child)) + if (childPreferredSize != mainAxisExtentForChild(child)) { child->setChildNeedsLayout(MarkOnlyThis); - else { + } else { // To avoid double applying margin changes in updateAutoMarginsInCrossAxis, we reset the margins here. resetAutoMarginsAndLogicalTopInCrossAxis(child); } - updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child); + // We may have already forced relayout for orthogonal flowing children in preferredMainAxisContentExtentForChild. + bool forceChildRelayout = relayoutChildren && !childPreferredMainAxisContentExtentRequiresLayout(child, hasInfiniteLineLength); + updateBlockChildDirtyBitsBeforeLayout(forceChildRelayout, child); child->layoutIfNeeded(); updateAutoMarginsInMainAxis(child, autoMarginOffset); LayoutUnit childCrossAxisMarginBoxExtent; - if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child)) { + if (alignmentForChild(child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(child)) { LayoutUnit ascent = marginBoxAscentForChild(child); LayoutUnit descent = (crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child)) - ascent; @@ -1105,8 +1135,9 @@ void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, cons maxDescent = std::max(maxDescent, descent); childCrossAxisMarginBoxExtent = maxAscent + maxDescent; - } else - childCrossAxisMarginBoxExtent = crossAxisExtentForChild(child) + crossAxisMarginExtentForChild(child); + } else { + childCrossAxisMarginBoxExtent = crossAxisIntrinsicExtentForChild(child) + crossAxisMarginExtentForChild(child); + } if (!isColumnFlow()) setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent())); maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent); @@ -1157,6 +1188,7 @@ void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, size_t seenInFlowPositionedChildren = 0; for (size_t i = 0; i < children.size(); ++i) { RenderBox* child = children[i]; + if (child->isOutOfFlowPositioned()) { child->layer()->setStaticBlockPosition(mainAxisOffset); continue; @@ -1175,6 +1207,8 @@ void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines) { + if (numberOfLines <= 1) + return 0; if (alignContent == AlignContentFlexEnd) return availableFreeSpace; if (alignContent == AlignContentCenter) @@ -1201,7 +1235,15 @@ static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace void RenderFlexibleBox::alignFlexLines(Vector<LineContext>& lineContexts) { - if (!isMultiline() || style()->alignContent() == AlignContentFlexStart) + // If we have a single line flexbox or a multiline line flexbox with only one flex line, + // 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 updateLogicalHeight. + if (lineContexts.size() == 1) { + lineContexts[0].crossAxisExtent = crossAxisContentExtent(); + return; + } + + if (style()->alignContent() == AlignContentFlexStart) return; LayoutUnit availableCrossAxisSpace = crossAxisContentExtent(); @@ -1260,25 +1302,25 @@ void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts) continue; switch (alignmentForChild(child)) { - case AlignAuto: + case ItemPositionAuto: ASSERT_NOT_REACHED(); break; - case AlignStretch: { + case ItemPositionStretch: { 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; } - case AlignFlexStart: + case ItemPositionFlexStart: break; - case AlignFlexEnd: + case ItemPositionFlexEnd: adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child)); break; - case AlignCenter: + case ItemPositionCenter: adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) / 2); break; - case AlignBaseline: { + case ItemPositionBaseline: { // FIXME: If we get here in columns, we want the use the descent, except we currently can't get the ascent/descent of orthogonal children. // https://bugs.webkit.org/show_bug.cgi?id=98076 LayoutUnit ascent = marginBoxAscentForChild(child); @@ -1289,6 +1331,16 @@ void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts) minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) - startOffset); break; } + case ItemPositionSelfStart: + case ItemPositionSelfEnd: + case ItemPositionStart: + case ItemPositionEnd: + case ItemPositionLeft: + case ItemPositionRight: + // FIXME: File a bug about implementing that. The extended grammar + // is not enabled by default so we shouldn't hit this codepath. + ASSERT_NOT_REACHED(); + break; } } minMarginAfterBaselines.append(minMarginAfterBaseline); @@ -1304,7 +1356,7 @@ void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts) LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber]; for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) { ASSERT(child); - if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child) && minMarginAfterBaseline) + if (alignmentForChild(child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(child) && minMarginAfterBaseline) adjustAlignmentForChild(child, minMarginAfterBaseline); } } @@ -1315,9 +1367,10 @@ void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox* child, LayoutUni if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) { // FIXME: If the child has orthogonal flow, then it already has an override height set, so use it. if (!hasOrthogonalFlow(child)) { - LayoutUnit stretchedLogicalHeight = child->logicalHeight() + availableAlignmentSpaceForChild(lineCrossAxisExtent, child); + LayoutUnit heightBeforeStretching = needToStretchChildLogicalHeight(child) ? constrainedChildIntrinsicContentLogicalHeight(child) : child->logicalHeight(); + LayoutUnit stretchedLogicalHeight = heightBeforeStretching + availableAlignmentSpaceForChildBeforeStretching(lineCrossAxisExtent, child); ASSERT(!child->needsLayout()); - LayoutUnit desiredLogicalHeight = child->constrainLogicalHeightByMinMax(stretchedLogicalHeight, child->logicalHeight() - child->borderAndPaddingLogicalHeight()); + LayoutUnit desiredLogicalHeight = child->constrainLogicalHeightByMinMax(stretchedLogicalHeight, heightBeforeStretching - child->borderAndPaddingLogicalHeight()); // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905. if (desiredLogicalHeight != child->logicalHeight()) { @@ -1330,7 +1383,7 @@ void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox* child, LayoutUni // FIXME: If the child doesn't have orthogonal flow, then it already has an override width set, so use it. if (hasOrthogonalFlow(child)) { LayoutUnit childWidth = std::max<LayoutUnit>(0, lineCrossAxisExtent - crossAxisMarginExtentForChild(child)); - childWidth = child->constrainLogicalWidthInRegionByMinMax(childWidth, childWidth, this); + childWidth = child->constrainLogicalWidthByMinMax(childWidth, childWidth, this); if (childWidth != child->logicalWidth()) { child->setOverrideLogicalContentWidth(childWidth - child->borderAndPaddingLogicalWidth()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderFlexibleBox.h b/chromium/third_party/WebKit/Source/core/rendering/RenderFlexibleBox.h index c9297da7001..6a34e899c34 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderFlexibleBox.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderFlexibleBox.h @@ -47,8 +47,8 @@ public: virtual bool isFlexibleBox() const OVERRIDE FINAL { return true; } virtual bool avoidsFloats() const OVERRIDE FINAL { return true; } - virtual bool canCollapseAnonymousBlockChild() const OVERRIDE FINAL { return false; } - virtual void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0) OVERRIDE FINAL; + virtual bool canCollapseAnonymousBlockChild() const OVERRIDE { return false; } + virtual void layoutBlock(bool relayoutChildren) OVERRIDE FINAL; virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const OVERRIDE; virtual int firstLineBoxBaseline() const OVERRIDE; @@ -61,9 +61,8 @@ public: protected: virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE; - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; + virtual void removeChild(RenderObject*) OVERRIDE; private: enum FlexSign { @@ -90,8 +89,10 @@ private: bool isLeftToRightFlow() const; bool isMultiline() const; Length flexBasisForChild(RenderBox* child) const; - void setCrossAxisExtent(LayoutUnit); LayoutUnit crossAxisExtentForChild(RenderBox* child) const; + LayoutUnit crossAxisIntrinsicExtentForChild(RenderBox* child) const; + LayoutUnit childIntrinsicHeight(RenderBox* child) const; + LayoutUnit childIntrinsicWidth(RenderBox* child) const; LayoutUnit mainAxisExtentForChild(RenderBox* child) const; LayoutUnit crossAxisExtent() const; LayoutUnit mainAxisExtent() const; @@ -110,19 +111,19 @@ private: LayoutUnit flowAwareMarginStartForChild(RenderBox* child) const; LayoutUnit flowAwareMarginEndForChild(RenderBox* child) const; LayoutUnit flowAwareMarginBeforeForChild(RenderBox* child) const; - LayoutUnit flowAwareMarginAfterForChild(RenderBox* child) const; LayoutUnit crossAxisMarginExtentForChild(RenderBox* child) const; LayoutUnit crossAxisScrollbarExtent() const; LayoutPoint flowAwareLocationForChild(RenderBox* child) const; // FIXME: Supporting layout deltas. void setFlowAwareLocationForChild(RenderBox* child, const LayoutPoint&); void adjustAlignmentForChild(RenderBox* child, LayoutUnit); - EAlignItems alignmentForChild(RenderBox* child) const; + ItemPosition alignmentForChild(RenderBox* child) const; LayoutUnit mainAxisBorderAndPaddingExtentForChild(RenderBox* child) const; - LayoutUnit mainAxisScrollbarExtentForChild(RenderBox* child) const; - LayoutUnit preferredMainAxisContentExtentForChild(RenderBox* child, bool hasInfiniteLineLength); + LayoutUnit preferredMainAxisContentExtentForChild(RenderBox* child, bool hasInfiniteLineLength, bool relayoutChildren = false); + bool childPreferredMainAxisContentExtentRequiresLayout(RenderBox* child, bool hasInfiniteLineLength) const; + bool needToStretchChildLogicalHeight(RenderBox* child) const; - void layoutFlexItems(bool relayoutChildren, Vector<LineContext>&); + void layoutFlexItems(bool relayoutChildren); LayoutUnit autoMarginOffsetInMainAxis(const OrderedFlexItemList&, LayoutUnit& availableFreeSpace); void updateAutoMarginsInMainAxis(RenderBox* child, LayoutUnit autoMarginOffset); bool hasAutoMarginsInCrossAxis(RenderBox* child) const; @@ -133,23 +134,23 @@ private: void repaintChildrenDuringLayoutIfMoved(const ChildFrameRects&); LayoutUnit availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox*); + LayoutUnit availableAlignmentSpaceForChildBeforeStretching(LayoutUnit lineCrossAxisExtent, RenderBox*); LayoutUnit marginBoxAscentForChild(RenderBox*); - LayoutUnit computeChildMarginValue(Length margin, RenderView*); + LayoutUnit computeChildMarginValue(Length margin); void prepareOrderIteratorAndMargins(); LayoutUnit adjustChildSizeForMinAndMax(RenderBox*, LayoutUnit childSize); // The hypothetical main size of an item is the flex base size clamped according to its min and max main size properties - bool computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& sumFlexBaseSize, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& sumHypotheticalMainSize, bool& hasInfiniteLineLength); + bool computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& sumFlexBaseSize, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& sumHypotheticalMainSize, bool& hasInfiniteLineLength, bool relayoutChildren); - bool resolveFlexibleLengths(FlexSign, const OrderedFlexItemList&, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize&, Vector<LayoutUnit>& childSizes, bool hasInfiniteLineLength); + bool resolveFlexibleLengths(FlexSign, const OrderedFlexItemList&, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize&, Vector<LayoutUnit, 16>& childSizes, bool hasInfiniteLineLength); void freezeViolations(const Vector<Violation>&, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize&, bool hasInfiniteLineLength); void resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox*); - bool needToStretchChild(RenderBox*); void setLogicalOverrideSize(RenderBox* child, LayoutUnit childPreferredSize); void prepareChildForPositionedLayout(RenderBox* child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset, PositionedLayoutMode); size_t numberOfInFlowPositionedChildren(const OrderedFlexItemList&) const; - void layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList&, const Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>&); + void layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList&, const Vector<LayoutUnit, 16>& childSizes, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>&, bool hasInfiniteLineLength); void layoutColumnReverse(const OrderedFlexItemList&, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace); void alignFlexLines(Vector<LineContext>&); void alignChildren(const Vector<LineContext>&); @@ -157,6 +158,9 @@ private: void flipForRightToLeftColumn(); void flipForWrapReverse(const Vector<LineContext>&, LayoutUnit crossAxisStartEdge); + // This is used to cache the preferred size for orthogonal flow children so we don't have to relayout to get it + HashMap<const RenderObject*, LayoutUnit> m_intrinsicSizeAlongMainAxis; + mutable OrderIterator m_orderIterator; int m_numberOfInFlowChildrenOnFirstLine; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderFlowThread.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderFlowThread.cpp index 2e9bb88992a..f239e9e5467 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderFlowThread.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderFlowThread.cpp @@ -35,9 +35,7 @@ #include "core/rendering/FlowThreadController.h" #include "core/rendering/HitTestRequest.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/PaintInfo.h" -#include "core/rendering/RenderBoxRegionInfo.h" #include "core/rendering/RenderInline.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderRegion.h" @@ -49,59 +47,13 @@ namespace WebCore { RenderFlowThread::RenderFlowThread() : RenderBlockFlow(0) - , m_previousRegionCount(0) - , m_autoLogicalHeightRegionsCount(0) , m_regionsInvalidated(false) - , m_regionsHaveUniformLogicalWidth(true) , m_regionsHaveUniformLogicalHeight(true) - , m_hasRegionsWithStyling(false) - , m_dispatchRegionLayoutUpdateEvent(false) - , m_dispatchRegionOversetChangeEvent(false) , m_pageLogicalSizeChanged(false) - , m_inConstrainedLayoutPhase(false) - , m_needsTwoPhasesLayout(false) { setFlowThreadState(InsideOutOfFlowThread); } -PassRefPtr<RenderStyle> RenderFlowThread::createFlowThreadStyle(RenderStyle* parentStyle) -{ - RefPtr<RenderStyle> newStyle(RenderStyle::create()); - newStyle->inheritFrom(parentStyle); - newStyle->setDisplay(BLOCK); - newStyle->setPosition(AbsolutePosition); - newStyle->setZIndex(0); - newStyle->setLeft(Length(0, Fixed)); - newStyle->setTop(Length(0, Fixed)); - newStyle->setWidth(Length(100, Percent)); - newStyle->setHeight(Length(100, Percent)); - newStyle->font().update(0); - - return newStyle.release(); -} - -void RenderFlowThread::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) -{ - RenderBlock::styleDidChange(diff, oldStyle); - - if (oldStyle && oldStyle->writingMode() != style()->writingMode()) - invalidateRegions(); -} - -void RenderFlowThread::removeFlowChildInfo(RenderObject* child) -{ - if (child->isBox()) - removeRenderBoxRegionInfo(toRenderBox(child)); - clearRenderObjectCustomStyle(child); -} - -void RenderFlowThread::addRegionToThread(RenderRegion* renderRegion) -{ - ASSERT(renderRegion); - m_regionList.add(renderRegion); - renderRegion->setIsValid(true); -} - void RenderFlowThread::removeRegionFromThread(RenderRegion* renderRegion) { ASSERT(renderRegion); @@ -116,9 +68,7 @@ void RenderFlowThread::invalidateRegions() } m_regionRangeMap.clear(); - m_breakBeforeToRegionMap.clear(); - m_breakAfterToRegionMap.clear(); - setNeedsLayout(); + setNeedsLayoutAndFullPaintInvalidation(); m_regionsInvalidated = true; } @@ -148,42 +98,24 @@ void RenderFlowThread::validateRegions() { if (m_regionsInvalidated) { m_regionsInvalidated = false; - m_regionsHaveUniformLogicalWidth = true; m_regionsHaveUniformLogicalHeight = true; if (hasRegions()) { - LayoutUnit previousRegionLogicalWidth = 0; LayoutUnit previousRegionLogicalHeight = 0; bool firstRegionVisited = false; for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; - ASSERT(!region->needsLayout() || region->isRenderRegionSet()); - - region->deleteAllRenderBoxRegionInfo(); - - // In the normal layout phase we need to initialize the computedAutoHeight for auto-height regions. - // See initializeRegionsComputedAutoHeight for the explanation. - // Also, if we have auto-height regions we can't assume m_regionsHaveUniformLogicalHeight to be true in the first phase - // because the auto-height regions don't have their height computed yet. - if (!inConstrainedLayoutPhase() && region->hasAutoLogicalHeight()) { - region->setComputedAutoHeight(region->maxPageLogicalHeight()); - m_regionsHaveUniformLogicalHeight = false; - } - - LayoutUnit regionLogicalWidth = region->pageLogicalWidth(); LayoutUnit regionLogicalHeight = region->pageLogicalHeight(); if (!firstRegionVisited) { firstRegionVisited = true; } else { - if (m_regionsHaveUniformLogicalWidth && previousRegionLogicalWidth != regionLogicalWidth) - m_regionsHaveUniformLogicalWidth = false; if (m_regionsHaveUniformLogicalHeight && previousRegionLogicalHeight != regionLogicalHeight) m_regionsHaveUniformLogicalHeight = false; } - previousRegionLogicalWidth = regionLogicalWidth; + previousRegionLogicalHeight = regionLogicalHeight; } } } @@ -194,54 +126,12 @@ void RenderFlowThread::validateRegions() void RenderFlowThread::layout() { - LayoutRectRecorder recorder(*this); m_pageLogicalSizeChanged = m_regionsInvalidated && everHadLayout(); - // In case this is the second pass of the normal phase we need to update the auto-height regions to their initial value. - // If the region chain was invalidated this will happen anyway. - if (!m_regionsInvalidated && !inConstrainedLayoutPhase()) - initializeRegionsComputedAutoHeight(); - - validateRegions(); - - // This is the first phase of the layout and because we have auto-height regions we'll need a second - // pass to update the flow with the computed auto-height regions. - m_needsTwoPhasesLayout = !inConstrainedLayoutPhase() && hasAutoLogicalHeightRegions(); - CurrentRenderFlowThreadMaintainer currentFlowThreadSetter(this); RenderBlockFlow::layout(); m_pageLogicalSizeChanged = false; - - if (lastRegion()) - lastRegion()->expandToEncompassFlowThreadContentsIfNeeded(); - - if (shouldDispatchRegionLayoutUpdateEvent()) - dispatchRegionLayoutUpdateEvent(); - - if (shouldDispatchRegionOversetChangeEvent()) - dispatchRegionOversetChangeEvent(); -} - -void RenderFlowThread::updateLogicalWidth() -{ - LayoutUnit logicalWidth = initialLogicalWidth(); - for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { - RenderRegion* region = *iter; - ASSERT(!region->needsLayout() || region->isRenderRegionSet()); - logicalWidth = max(region->pageLogicalWidth(), logicalWidth); - } - setLogicalWidth(logicalWidth); - - // If the regions have non-uniform logical widths, then insert inset information for the RenderFlowThread. - for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { - RenderRegion* region = *iter; - LayoutUnit regionLogicalWidth = region->pageLogicalWidth(); - if (regionLogicalWidth != logicalWidth) { - LayoutUnit logicalLeft = style()->direction() == LTR ? LayoutUnit() : logicalWidth - regionLogicalWidth; - region->setRenderBoxRegionInfo(this, logicalLeft, regionLogicalWidth, false); - } - } } void RenderFlowThread::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const @@ -251,104 +141,15 @@ void RenderFlowThread::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, L for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; - ASSERT(!region->needsLayout() || region->isRenderRegionSet()); - computedValues.m_extent += region->logicalHeightOfAllFlowThreadContent(); } } -LayoutRect RenderFlowThread::computeRegionClippingRect(const LayoutPoint& offset, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect) const -{ - LayoutRect regionClippingRect(offset + (flowThreadPortionOverflowRect.location() - flowThreadPortionRect.location()), flowThreadPortionOverflowRect.size()); - if (style()->isFlippedBlocksWritingMode()) - regionClippingRect.move(flowThreadPortionRect.size() - flowThreadPortionOverflowRect.size()); - return regionClippingRect; -} - -void RenderFlowThread::paintFlowThreadPortionInRegion(PaintInfo& paintInfo, RenderRegion* region, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const LayoutPoint& paintOffset) const -{ - GraphicsContext* context = paintInfo.context; - if (!context) - return; - - // RenderFlowThread should start painting its content in a position that is offset - // from the region rect's current position. The amount of offset is equal to the location of - // the flow thread portion in the flow thread's local coordinates. - // Note that we have to pixel snap the location at which we're going to paint, since this is necessary - // to minimize the amount of incorrect snapping that would otherwise occur. - // If we tried to paint by applying a non-integral translation, then all the - // layout code that attempted to pixel snap would be incorrect. - IntPoint adjustedPaintOffset; - LayoutPoint portionLocation; - if (style()->isFlippedBlocksWritingMode()) { - LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect); - flipForWritingMode(flippedFlowThreadPortionRect); - portionLocation = flippedFlowThreadPortionRect.location(); - } else { - portionLocation = flowThreadPortionRect.location(); - } - adjustedPaintOffset = roundedIntPoint(paintOffset - portionLocation); - - // The clipping rect for the region is set up by assuming the flowThreadPortionRect is going to paint offset from adjustedPaintOffset. - // Remember that we pixel snapped and moved the paintOffset and stored the snapped result in adjustedPaintOffset. Now we add back in - // the flowThreadPortionRect's location to get the spot where we expect the portion to actually paint. This can be non-integral and - // that's ok. We then pixel snap the resulting clipping rect to account for snapping that will occur when the flow thread paints. - IntRect regionClippingRect = pixelSnappedIntRect(computeRegionClippingRect(adjustedPaintOffset + portionLocation, flowThreadPortionRect, flowThreadPortionOverflowRect)); - - PaintInfo info(paintInfo); - info.rect.intersect(regionClippingRect); - - if (!info.rect.isEmpty()) { - context->save(); - - context->clip(regionClippingRect); - - context->translate(adjustedPaintOffset.x(), adjustedPaintOffset.y()); - info.rect.moveBy(-adjustedPaintOffset); - - if (info.phase == PaintPhaseTextClip) - info.paintBehavior = PaintBehaviorForceBlackText; - - layer()->paint(context, info.rect, info.paintBehavior, 0, region, PaintLayerTemporaryClipRects); - - context->restore(); - } -} - bool RenderFlowThread::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { if (hitTestAction == HitTestBlockBackground) return false; - return RenderBlock::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction); -} - -bool RenderFlowThread::hitTestFlowThreadPortionInRegion(RenderRegion* region, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const -{ - LayoutRect regionClippingRect = computeRegionClippingRect(accumulatedOffset, flowThreadPortionRect, flowThreadPortionOverflowRect); - if (!regionClippingRect.contains(locationInContainer.point())) - return false; - - LayoutSize renderFlowThreadOffset; - if (style()->isFlippedBlocksWritingMode()) { - LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect); - flipForWritingMode(flippedFlowThreadPortionRect); - renderFlowThreadOffset = accumulatedOffset - flippedFlowThreadPortionRect.location(); - } else { - renderFlowThreadOffset = accumulatedOffset - flowThreadPortionRect.location(); - } - - // Always ignore clipping, since the RenderFlowThread has nothing to do with the bounds of the FrameView. - HitTestRequest newRequest(request.type() | HitTestRequest::IgnoreClipping | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent); - - // Make a new temporary HitTestLocation in the new region. - HitTestLocation newHitTestLocation(locationInContainer, -renderFlowThreadOffset, region); - - bool isPointInsideFlowThread = layer()->hitTest(newRequest, newHitTestLocation, result); - - // FIXME: Should we set result.m_localPoint back to the RenderRegion's coordinate space or leave it in the RenderFlowThread's coordinate - // space? Right now it's staying in the RenderFlowThread's coordinate space, which may end up being ok. We will know more when we get around to - // patching positionForPoint. - return isPointInsideFlowThread; + return RenderBlockFlow::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction); } bool RenderFlowThread::shouldRepaint(const LayoutRect& r) const @@ -364,7 +165,7 @@ void RenderFlowThread::repaintRectangleInRegions(const LayoutRect& repaintRect) if (!shouldRepaint(repaintRect) || !hasValidRegionInfo()) return; - LayoutStateDisabler layoutStateDisabler(view()); // We can't use layout state to repaint, since the regions are somewhere else. + ForceHorriblySlowRectMapping slowRectMapping(*this); // We can't use layout state to repaint, since the regions are somewhere else. // We can't use currentFlowThread as it is possible to have interleaved flow threads and the wrong one could be used. // Let each region figure out the proper enclosing flow thread. @@ -377,13 +178,10 @@ void RenderFlowThread::repaintRectangleInRegions(const LayoutRect& repaintRect) } } -RenderRegion* RenderFlowThread::regionAtBlockOffset(LayoutUnit offset, bool extendLastRegion, RegionAutoGenerationPolicy autoGenerationPolicy) +RenderRegion* RenderFlowThread::regionAtBlockOffset(LayoutUnit offset) const { ASSERT(!m_regionsInvalidated); - if (autoGenerationPolicy == AllowRegionAutoGeneration) - autoGenerateRegionsToBlockOffset(offset); - if (offset <= 0) return m_regionList.isEmpty() ? 0 : m_regionList.first(); @@ -391,38 +189,12 @@ RenderRegion* RenderFlowThread::regionAtBlockOffset(LayoutUnit offset, bool exte m_regionIntervalTree.allOverlapsWithAdapter<RegionSearchAdapter>(adapter); // If no region was found, the offset is in the flow thread overflow. - // The last region will contain the offset if extendLastRegion is set or if the last region is a set. - if (!adapter.result() && !m_regionList.isEmpty() && (extendLastRegion || m_regionList.last()->isRenderRegionSet())) + if (!adapter.result() && !m_regionList.isEmpty()) return m_regionList.last(); return adapter.result(); } -RenderRegion* RenderFlowThread::regionFromAbsolutePointAndBox(IntPoint absolutePoint, const RenderBox* flowedBox) -{ - if (!flowedBox) - return 0; - - RenderRegion* startRegion = 0; - RenderRegion* endRegion = 0; - getRegionRangeForBox(flowedBox, startRegion, endRegion); - - if (!startRegion) - return 0; - - for (RenderRegionList::iterator iter = m_regionList.find(startRegion); iter != m_regionList.end(); ++iter) { - RenderRegion* region = *iter; - IntRect regionAbsoluteRect(roundedIntPoint(region->localToAbsolute()), roundedIntSize(region->frameRect().size())); - if (regionAbsoluteRect.contains(absolutePoint)) - return region; - - if (region == endRegion) - break; - } - - return 0; -} - LayoutPoint RenderFlowThread::adjustedPositionRelativeToOffsetParent(const RenderBoxModelObject& boxModelObject, const LayoutPoint& startPoint) { LayoutPoint referencePoint = startPoint; @@ -430,9 +202,8 @@ LayoutPoint RenderFlowThread::adjustedPositionRelativeToOffsetParent(const Rende // FIXME: This needs to be adapted for different writing modes inside the flow thread. RenderRegion* startRegion = regionAtBlockOffset(referencePoint.y()); if (startRegion) { - RenderBoxModelObject* startRegionBox = startRegion->isRenderNamedFlowFragment() ? toRenderBoxModelObject(startRegion->parent()) : startRegion; // Take into account the offset coordinates of the region. - RenderObject* currObject = startRegionBox; + RenderObject* currObject = startRegion; RenderObject* currOffsetParentRenderer; Element* currOffsetParentElement; while ((currOffsetParentElement = currObject->offsetParent()) && (currOffsetParentRenderer = currOffsetParentElement->renderer())) { @@ -452,7 +223,7 @@ LayoutPoint RenderFlowThread::adjustedPositionRelativeToOffsetParent(const Rende // and is no longer valid) and recompute it using the region in which it flows as reference. bool wasComputedRelativeToOtherRegion = false; const RenderBlock* objContainingBlock = boxModelObject.containingBlock(); - while (objContainingBlock && !objContainingBlock->isRenderNamedFlowThread()) { + while (objContainingBlock) { // Check if this object is in a different region. RenderRegion* parentStartRegion = 0; RenderRegion* parentEndRegion = 0; @@ -465,12 +236,6 @@ LayoutPoint RenderFlowThread::adjustedPositionRelativeToOffsetParent(const Rende } if (wasComputedRelativeToOtherRegion) { - if (boxModelObject.isBox()) { - // Use borderBoxRectInRegion to account for variations such as percentage margins. - LayoutRect borderBoxRect = toRenderBox(&boxModelObject)->borderBoxRectInRegion(startRegion, RenderBox::DoNotCacheRenderBoxRegionInfo); - referencePoint.move(borderBoxRect.location().x(), 0); - } - // Get the logical top coordinate of the current object. LayoutUnit top = 0; if (boxModelObject.isRenderBlock()) { @@ -489,7 +254,7 @@ LayoutPoint RenderFlowThread::adjustedPositionRelativeToOffsetParent(const Rende // and compute the object's top, relative to the region's top. LayoutUnit regionLogicalTop = startRegion->pageLogicalTopForOffset(top); LayoutUnit topRelativeToRegion = top - regionLogicalTop; - referencePoint.setY(startRegionBox->offsetTop() + topRelativeToRegion); + referencePoint.setY(startRegion->offsetTop() + topRelativeToRegion); // Since the top has been overriden, check if the // relative/sticky positioning must be reconsidered. @@ -501,7 +266,7 @@ LayoutPoint RenderFlowThread::adjustedPositionRelativeToOffsetParent(const Rende // Since we're looking for the offset relative to the body, we must also // take into consideration the borders of the region. - referencePoint.move(startRegionBox->borderLeft(), startRegionBox->borderTop()); + referencePoint.move(startRegion->borderLeft(), startRegion->borderTop()); } return referencePoint; @@ -513,12 +278,6 @@ LayoutUnit RenderFlowThread::pageLogicalTopForOffset(LayoutUnit offset) return region ? region->pageLogicalTopForOffset(offset) : LayoutUnit(); } -LayoutUnit RenderFlowThread::pageLogicalWidthForOffset(LayoutUnit offset) -{ - RenderRegion* region = regionAtBlockOffset(offset, true); - return region ? region->pageLogicalWidth() : contentLogicalWidth(); -} - LayoutUnit RenderFlowThread::pageLogicalHeightForOffset(LayoutUnit offset) { RenderRegion* region = regionAtBlockOffset(offset); @@ -546,125 +305,6 @@ LayoutUnit RenderFlowThread::pageRemainingLogicalHeightForOffset(LayoutUnit offs return remainingHeight; } -RenderRegion* RenderFlowThread::mapFromFlowToRegion(TransformState& transformState) const -{ - if (!hasValidRegionInfo()) - return 0; - - LayoutRect boxRect = transformState.mappedQuad().enclosingBoundingBox(); - flipForWritingMode(boxRect); - - // FIXME: We need to refactor RenderObject::absoluteQuads to be able to split the quads across regions, - // for now we just take the center of the mapped enclosing box and map it to a region. - // Note: Using the center in order to avoid rounding errors. - - LayoutPoint center = boxRect.center(); - RenderRegion* renderRegion = const_cast<RenderFlowThread*>(this)->regionAtBlockOffset(isHorizontalWritingMode() ? center.y() : center.x(), true, DisallowRegionAutoGeneration); - if (!renderRegion) - return 0; - - LayoutRect flippedRegionRect(renderRegion->flowThreadPortionRect()); - flipForWritingMode(flippedRegionRect); - - transformState.move(renderRegion->contentBoxRect().location() - flippedRegionRect.location()); - - return renderRegion; -} - -void RenderFlowThread::removeRenderBoxRegionInfo(RenderBox* box) -{ - if (!hasRegions()) - return; - - // If the region chain was invalidated the next layout will clear the box information from all the regions. - if (m_regionsInvalidated) { - ASSERT(selfNeedsLayout()); - return; - } - - RenderRegion* startRegion; - RenderRegion* endRegion; - getRegionRangeForBox(box, startRegion, endRegion); - - for (RenderRegionList::iterator iter = m_regionList.find(startRegion); iter != m_regionList.end(); ++iter) { - RenderRegion* region = *iter; - region->removeRenderBoxRegionInfo(box); - if (region == endRegion) - break; - } - -#ifndef NDEBUG - // 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; - ASSERT(!region->renderBoxRegionInfo(box)); - } -#endif - - m_regionRangeMap.remove(box); -} - -bool RenderFlowThread::logicalWidthChangedInRegionsForBlock(const RenderBlock* block) -{ - if (!hasRegions()) - return false; - - RenderRegion* startRegion; - RenderRegion* endRegion; - getRegionRangeForBox(block, startRegion, endRegion); - - // When the region chain is invalidated the box information is discarded so we must assume the width has changed. - if (m_pageLogicalSizeChanged && !startRegion) - return true; - - // Not necessary for the flow thread, since we already computed the correct info for it. - if (block == this) - return false; - - for (RenderRegionList::iterator iter = m_regionList.find(startRegion); iter != m_regionList.end(); ++iter) { - RenderRegion* region = *iter; - ASSERT(!region->needsLayout() || region->isRenderRegionSet()); - - OwnPtr<RenderBoxRegionInfo> oldInfo = region->takeRenderBoxRegionInfo(block); - if (!oldInfo) - continue; - - LayoutUnit oldLogicalWidth = oldInfo->logicalWidth(); - RenderBoxRegionInfo* newInfo = block->renderBoxRegionInfo(region); - if (!newInfo || newInfo->logicalWidth() != oldLogicalWidth) - return true; - - if (region == endRegion) - break; - } - - return false; -} - -LayoutUnit RenderFlowThread::contentLogicalWidthOfFirstRegion() const -{ - RenderRegion* firstValidRegionInFlow = firstRegion(); - if (!firstValidRegionInFlow) - return 0; - return isHorizontalWritingMode() ? firstValidRegionInFlow->contentWidth() : firstValidRegionInFlow->contentHeight(); -} - -LayoutUnit RenderFlowThread::contentLogicalHeightOfFirstRegion() const -{ - RenderRegion* firstValidRegionInFlow = firstRegion(); - if (!firstValidRegionInFlow) - return 0; - return isHorizontalWritingMode() ? firstValidRegionInFlow->contentHeight() : firstValidRegionInFlow->contentWidth(); -} - -LayoutUnit RenderFlowThread::contentLogicalLeftOfFirstRegion() const -{ - RenderRegion* firstValidRegionInFlow = firstRegion(); - if (!firstValidRegionInFlow) - return 0; - return isHorizontalWritingMode() ? firstValidRegionInFlow->flowThreadPortionRect().x() : firstValidRegionInFlow->flowThreadPortionRect().y(); -} - RenderRegion* RenderFlowThread::firstRegion() const { if (!hasValidRegionInfo()) @@ -679,44 +319,17 @@ RenderRegion* RenderFlowThread::lastRegion() const return m_regionList.last(); } -void RenderFlowThread::clearRenderObjectCustomStyle(const RenderObject* object, - const RenderRegion* oldStartRegion, const RenderRegion* oldEndRegion, - const RenderRegion* newStartRegion, const RenderRegion* newEndRegion) -{ - // Clear the styles for the object in the regions. - // The styles are not cleared for the regions that are contained in both ranges. - bool insideOldRegionRange = false; - bool insideNewRegionRange = false; - for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { - RenderRegion* region = *iter; - - if (oldStartRegion == region) - insideOldRegionRange = true; - if (newStartRegion == region) - insideNewRegionRange = true; - - if (!(insideOldRegionRange && insideNewRegionRange)) - region->clearObjectStyleInRegion(object); - - if (oldEndRegion == region) - insideOldRegionRange = false; - if (newEndRegion == region) - insideNewRegionRange = false; - } -} - void RenderFlowThread::setRegionRangeForBox(const RenderBox* box, LayoutUnit offsetFromLogicalTopOfFirstPage) { if (!hasRegions()) return; // FIXME: Not right for differing writing-modes. - RenderRegion* startRegion = regionAtBlockOffset(offsetFromLogicalTopOfFirstPage, true); - RenderRegion* endRegion = regionAtBlockOffset(offsetFromLogicalTopOfFirstPage + box->logicalHeight(), true); + RenderRegion* startRegion = regionAtBlockOffset(offsetFromLogicalTopOfFirstPage); + RenderRegion* endRegion = regionAtBlockOffset(offsetFromLogicalTopOfFirstPage + box->logicalHeight()); RenderRegionRangeMap::iterator it = m_regionRangeMap.find(box); if (it == m_regionRangeMap.end()) { m_regionRangeMap.set(box, RenderRegionRange(startRegion, endRegion)); - clearRenderObjectCustomStyle(box); return; } @@ -725,21 +338,6 @@ void RenderFlowThread::setRegionRangeForBox(const RenderBox* box, LayoutUnit off if (range.startRegion() == startRegion && range.endRegion() == endRegion) return; - // Delete any info that we find before our new startRegion and after our new endRegion. - for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { - RenderRegion* region = *iter; - if (region == startRegion) { - iter = m_regionList.find(endRegion); - continue; - } - - region->removeRenderBoxRegionInfo(box); - - if (region == range.endRegion()) - break; - } - - clearRenderObjectCustomStyle(box, range.startRegion(), range.endRegion(), startRegion, endRegion); range.setRange(startRegion, endRegion); } @@ -757,148 +355,15 @@ void RenderFlowThread::getRegionRangeForBox(const RenderBox* box, RenderRegion*& ASSERT(m_regionList.contains(startRegion) && m_regionList.contains(endRegion)); } -void RenderFlowThread::applyBreakAfterContent(LayoutUnit clientHeight) -{ - // Simulate a region break at height. If it points inside an auto logical height region, - // then it may determine the region computed autoheight. - addForcedRegionBreak(clientHeight, this, false); -} - -bool RenderFlowThread::regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const -{ - ASSERT(targetRegion); - - for (RenderRegionList::const_iterator it = m_regionList.find(const_cast<RenderRegion*>(startRegion)); it != m_regionList.end(); ++it) { - const RenderRegion* currRegion = *it; - if (targetRegion == currRegion) - return true; - if (currRegion == endRegion) - break; - } - - return false; -} - -// Check if the content is flown into at least a region with region styling rules. -void RenderFlowThread::checkRegionsWithStyling() -{ - bool hasRegionsWithStyling = false; - for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { - RenderRegion* region = *iter; - if (region->hasCustomRegionStyle()) { - hasRegionsWithStyling = true; - break; - } - } - m_hasRegionsWithStyling = hasRegionsWithStyling; -} - -bool RenderFlowThread::objectInFlowRegion(const RenderObject* object, const RenderRegion* region) const -{ - ASSERT(object); - ASSERT(region); - - RenderFlowThread* flowThread = object->flowThreadContainingBlock(); - if (flowThread != this) - return false; - if (!m_regionList.contains(const_cast<RenderRegion*>(region))) - return false; - - RenderBox* enclosingBox = object->enclosingBox(); - RenderRegion* enclosingBoxStartRegion = 0; - RenderRegion* enclosingBoxEndRegion = 0; - getRegionRangeForBox(enclosingBox, enclosingBoxStartRegion, enclosingBoxEndRegion); - if (!regionInRange(region, enclosingBoxStartRegion, enclosingBoxEndRegion)) - return false; - - if (object->isBox()) - return true; - - LayoutRect objectABBRect = object->absoluteBoundingBoxRect(true); - if (!objectABBRect.width()) - objectABBRect.setWidth(1); - if (!objectABBRect.height()) - objectABBRect.setHeight(1); - if (objectABBRect.intersects(region->absoluteBoundingBoxRect(true))) - return true; - - if (region == lastRegion()) { - // If the object does not intersect any of the enclosing box regions - // then the object is in last region. - for (RenderRegionList::const_iterator it = m_regionList.find(enclosingBoxStartRegion); it != m_regionList.end(); ++it) { - const RenderRegion* currRegion = *it; - if (currRegion == region) - break; - if (objectABBRect.intersects(currRegion->absoluteBoundingBoxRect(true))) - return false; - } - return true; - } - - return false; -} - -#ifndef NDEBUG -bool RenderFlowThread::isAutoLogicalHeightRegionsCountConsistent() const -{ - unsigned autoLogicalHeightRegions = 0; - for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { - const RenderRegion* region = *iter; - if (region->hasAutoLogicalHeight()) - autoLogicalHeightRegions++; - } - - return autoLogicalHeightRegions == m_autoLogicalHeightRegionsCount; -} -#endif - -// During the normal layout phase of the named flow the regions are initialized with a height equal to their max-height. -// This way unforced breaks are automatically placed when a region is full and the content height/position correctly estimated. -// Also, the region where a forced break falls is exactly the region found at the forced break offset inside the flow content. -void RenderFlowThread::initializeRegionsComputedAutoHeight(RenderRegion* startRegion) -{ - ASSERT(!inConstrainedLayoutPhase()); - if (!hasAutoLogicalHeightRegions()) - return; - - RenderRegionList::iterator regionIter = startRegion ? m_regionList.find(startRegion) : m_regionList.begin(); - for (; regionIter != m_regionList.end(); ++regionIter) { - RenderRegion* region = *regionIter; - if (region->hasAutoLogicalHeight()) - region->setComputedAutoHeight(region->maxPageLogicalHeight()); - } -} - -void RenderFlowThread::markAutoLogicalHeightRegionsForLayout() +void RenderFlowThread::updateRegionsFlowThreadPortionRect() { - ASSERT(hasAutoLogicalHeightRegions()); - - for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { - RenderRegion* region = *iter; - if (!region->hasAutoLogicalHeight()) - continue; - - // FIXME: We need to find a way to avoid marking all the regions ancestors for layout - // as we are already inside layout. - region->setNeedsLayout(); - } -} - -void RenderFlowThread::updateRegionsFlowThreadPortionRect(const RenderRegion* lastRegionWithContent) -{ - ASSERT(!lastRegionWithContent || (!inConstrainedLayoutPhase() && hasAutoLogicalHeightRegions())); LayoutUnit logicalHeight = 0; - bool emptyRegionsSegment = false; // FIXME: Optimize not to clear the interval all the time. This implies manually managing the tree nodes lifecycle. m_regionIntervalTree.clear(); m_regionIntervalTree.initIfNeeded(); for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; - // If we find an empty auto-height region, clear the computedAutoHeight value. - if (emptyRegionsSegment && region->hasAutoLogicalHeight()) - region->clearComputedAutoHeight(); - LayoutUnit regionLogicalWidth = region->pageLogicalWidth(); LayoutUnit regionLogicalHeight = std::min<LayoutUnit>(RenderFlowThread::maxLogicalHeight() - logicalHeight, region->logicalHeightOfAllFlowThreadContent()); @@ -909,104 +374,7 @@ void RenderFlowThread::updateRegionsFlowThreadPortionRect(const RenderRegion* la m_regionIntervalTree.add(RegionIntervalTree::createInterval(logicalHeight, logicalHeight + regionLogicalHeight, region)); logicalHeight += regionLogicalHeight; - - // Once we find the last region with content the next regions are considered empty. - if (lastRegionWithContent == region) - emptyRegionsSegment = true; } - - ASSERT(!lastRegionWithContent || emptyRegionsSegment); -} - -// Even if we require the break to occur at offsetBreakInFlowThread, because regions may have min/max-height values, -// it is possible that the break will occur at a different offset than the original one required. -// offsetBreakAdjustment measures the different between the requested break offset and the current break offset. -bool RenderFlowThread::addForcedRegionBreak(LayoutUnit offsetBreakInFlowThread, RenderObject* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment) -{ - // We take breaks into account for height computation for auto logical height regions - // only in the layout phase in which we lay out the flows threads unconstrained - // and we use the content breaks to determine the computedAutoHeight for - // auto logical height regions. - if (inConstrainedLayoutPhase()) - return false; - - // Breaks can come before or after some objects. We need to track these objects, so that if we get - // multiple breaks for the same object (for example because of multiple layouts on the same object), - // we need to invalidate every other region after the old one and start computing from fresh. - RenderObjectToRegionMap& mapToUse = isBefore ? m_breakBeforeToRegionMap : m_breakAfterToRegionMap; - RenderObjectToRegionMap::iterator iter = mapToUse.find(breakChild); - if (iter != mapToUse.end()) { - RenderRegionList::iterator regionIter = m_regionList.find(iter->value); - ASSERT_WITH_SECURITY_IMPLICATION(regionIter != m_regionList.end()); - ASSERT((*regionIter)->hasAutoLogicalHeight()); - initializeRegionsComputedAutoHeight(*regionIter); - - // We need to update the regions flow thread portion rect because we are going to process - // a break on these regions. - updateRegionsFlowThreadPortionRect(); - } - - // Simulate a region break at offsetBreakInFlowThread. If it points inside an auto logical height region, - // then it determines the region computed auto height. - RenderRegion* region = regionAtBlockOffset(offsetBreakInFlowThread); - if (!region) - return false; - - bool lastBreakAfterContent = breakChild == this; - bool hasComputedAutoHeight = false; - - LayoutUnit currentRegionOffsetInFlowThread = isHorizontalWritingMode() ? region->flowThreadPortionRect().y() : region->flowThreadPortionRect().x(); - LayoutUnit offsetBreakInCurrentRegion = offsetBreakInFlowThread - currentRegionOffsetInFlowThread; - - if (region->hasAutoLogicalHeight()) { - // A forced break can appear only in an auto-height region that didn't have a forced break before. - // This ASSERT is a good-enough heuristic to verify the above condition. - ASSERT(region->maxPageLogicalHeight() == region->computedAutoHeight()); - - mapToUse.set(breakChild, region); - - hasComputedAutoHeight = true; - - // Compute the region height pretending that the offsetBreakInCurrentRegion is the logicalHeight for the auto-height region. - LayoutUnit regionComputedAutoHeight = region->constrainContentBoxLogicalHeightByMinMax(offsetBreakInCurrentRegion, -1); - - // The new height of this region needs to be smaller than the initial value, the max height. A forced break is the only way to change the initial - // height of an auto-height region besides content ending. - ASSERT(regionComputedAutoHeight <= region->maxPageLogicalHeight()); - - region->setComputedAutoHeight(regionComputedAutoHeight); - - currentRegionOffsetInFlowThread += regionComputedAutoHeight; - } else { - currentRegionOffsetInFlowThread += isHorizontalWritingMode() ? region->flowThreadPortionRect().height() : region->flowThreadPortionRect().width(); - } - - // If the break was found inside an auto-height region its size changed so we need to recompute the flow thread portion rectangles. - // Also, if this is the last break after the content we need to clear the computedAutoHeight value on the last empty regions. - if (hasAutoLogicalHeightRegions() && lastBreakAfterContent) - updateRegionsFlowThreadPortionRect(region); - else if (hasComputedAutoHeight) - updateRegionsFlowThreadPortionRect(); - - if (offsetBreakAdjustment) - *offsetBreakAdjustment = max<LayoutUnit>(0, currentRegionOffsetInFlowThread - offsetBreakInFlowThread); - - return hasComputedAutoHeight; -} - -void RenderFlowThread::incrementAutoLogicalHeightRegions() -{ - if (!m_autoLogicalHeightRegionsCount) - view()->flowThreadController()->incrementFlowThreadsWithAutoLogicalHeightRegions(); - ++m_autoLogicalHeightRegionsCount; -} - -void RenderFlowThread::decrementAutoLogicalHeightRegions() -{ - ASSERT(m_autoLogicalHeightRegionsCount > 0); - --m_autoLogicalHeightRegionsCount; - if (!m_autoLogicalHeightRegionsCount) - view()->flowThreadController()->decrementFlowThreadsWithAutoLogicalHeightRegions(); } void RenderFlowThread::collectLayerFragments(LayerFragments& layerFragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect) @@ -1070,18 +438,18 @@ const RenderBox* RenderFlowThread::currentStatePusherRenderBox() const return 0; } -void RenderFlowThread::pushFlowThreadLayoutState(const RenderObject* object) +void RenderFlowThread::pushFlowThreadLayoutState(const RenderObject& object) { if (const RenderBox* currentBoxDescendant = currentStatePusherRenderBox()) { LayoutState* layoutState = currentBoxDescendant->view()->layoutState(); if (layoutState && layoutState->isPaginated()) { ASSERT(layoutState->renderer() == currentBoxDescendant); - LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset; + LayoutSize offsetDelta = layoutState->layoutOffset() - layoutState->pageOffset(); setOffsetFromLogicalTopOfFirstRegion(currentBoxDescendant, currentBoxDescendant->isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width()); } } - m_statePusherObjectsStack.add(object); + m_statePusherObjectsStack.add(&object); } void RenderFlowThread::popFlowThreadLayoutState() @@ -1109,7 +477,7 @@ LayoutUnit RenderFlowThread::offsetFromLogicalTopOfFirstRegion(const RenderBlock LayoutState* layoutState = view()->layoutState(); ASSERT(layoutState->renderer() == currentBlock); ASSERT(layoutState && layoutState->isPaginated()); - LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset; + LayoutSize offsetDelta = layoutState->layoutOffset() - layoutState->pageOffset(); return currentBoxDescendant->isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width(); } @@ -1148,17 +516,6 @@ void RenderFlowThread::RegionSearchAdapter::collectIfNeeded(const RegionInterval m_result = interval.data(); } -void RenderFlowThread::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const -{ - if (this == repaintContainer) - return; - - if (RenderRegion* region = mapFromFlowToRegion(transformState)) { - // FIXME: The cast below is probably not the best solution, we may need to find a better way. - static_cast<const RenderObject*>(region)->mapLocalToContainer(region->containerForRepaint(), transformState, mode, wasFixed); - } -} - CurrentRenderFlowThreadMaintainer::CurrentRenderFlowThreadMaintainer(RenderFlowThread* renderFlowThread) : m_renderFlowThread(renderFlowThread) , m_previousRenderFlowThread(0) @@ -1167,7 +524,6 @@ CurrentRenderFlowThreadMaintainer::CurrentRenderFlowThreadMaintainer(RenderFlowT return; RenderView* view = m_renderFlowThread->view(); m_previousRenderFlowThread = view->flowThreadController()->currentRenderFlowThread(); - ASSERT(!m_previousRenderFlowThread || !renderFlowThread->isRenderNamedFlowThread()); view->flowThreadController()->setCurrentRenderFlowThread(m_renderFlowThread); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderFlowThread.h b/chromium/third_party/WebKit/Source/core/rendering/RenderFlowThread.h index 7986768361e..12c92fb627b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderFlowThread.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderFlowThread.h @@ -41,7 +41,6 @@ namespace WebCore { struct LayerFragment; typedef Vector<LayerFragment, 1> LayerFragments; class RenderFlowThread; -class RenderStyle; class RenderRegion; typedef ListHashSet<RenderRegion*> RenderRegionList; @@ -58,117 +57,58 @@ public: virtual ~RenderFlowThread() { }; virtual bool isRenderFlowThread() const OVERRIDE FINAL { return true; } + virtual bool isRenderMultiColumnFlowThread() const { return false; } - virtual void layout() OVERRIDE FINAL; + virtual void layout() OVERRIDE; // Always create a RenderLayer for the RenderFlowThread so that we // can easily avoid drawing the children directly. - virtual bool requiresLayer() const OVERRIDE FINAL { return true; } + virtual LayerType layerTypeRequired() const OVERRIDE FINAL { return NormalLayer; } - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE FINAL; - void removeFlowChildInfo(RenderObject*); -#ifndef NDEBUG - bool hasChildInfo(RenderObject* child) const { return child && child->isBox() && m_regionRangeMap.contains(toRenderBox(child)); } -#endif - - virtual void addRegionToThread(RenderRegion*); + virtual void addRegionToThread(RenderRegion*) = 0; virtual void removeRegionFromThread(RenderRegion*); const RenderRegionList& renderRegionList() const { return m_regionList; } - virtual void updateLogicalWidth() OVERRIDE FINAL; virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE; - void paintFlowThreadPortionInRegion(PaintInfo&, RenderRegion*, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const LayoutPoint&) const; - bool hitTestFlowThreadPortionInRegion(RenderRegion*, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const; - bool hasRegions() const { return m_regionList.size(); } - // Check if the content is flown into at least a region with region styling rules. - bool hasRegionsWithStyling() const { return m_hasRegionsWithStyling; } - void checkRegionsWithStyling(); - virtual void regionChangedWritingMode(RenderRegion*) { } void validateRegions(); void invalidateRegions(); bool hasValidRegionInfo() const { return !m_regionsInvalidated && !m_regionList.isEmpty(); } - static PassRefPtr<RenderStyle> createFlowThreadStyle(RenderStyle* parentStyle); - - void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - void repaintRectangleInRegions(const LayoutRect&) const; LayoutPoint adjustedPositionRelativeToOffsetParent(const RenderBoxModelObject&, const LayoutPoint&); LayoutUnit pageLogicalTopForOffset(LayoutUnit); - LayoutUnit pageLogicalWidthForOffset(LayoutUnit); LayoutUnit pageLogicalHeightForOffset(LayoutUnit); LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit, PageBoundaryRule = IncludePageBoundary); virtual void setPageBreak(LayoutUnit /*offset*/, LayoutUnit /*spaceShortage*/) { } virtual void updateMinimumPageHeight(LayoutUnit /*offset*/, LayoutUnit /*minHeight*/) { } - enum RegionAutoGenerationPolicy { - AllowRegionAutoGeneration, - DisallowRegionAutoGeneration, - }; - RenderRegion* regionAtBlockOffset(LayoutUnit, bool extendLastRegion = false, RegionAutoGenerationPolicy = AllowRegionAutoGeneration); - - RenderRegion* regionFromAbsolutePointAndBox(IntPoint, const RenderBox* flowedBox); + virtual RenderRegion* regionAtBlockOffset(LayoutUnit) const; - bool regionsHaveUniformLogicalWidth() const { return m_regionsHaveUniformLogicalWidth; } bool regionsHaveUniformLogicalHeight() const { return m_regionsHaveUniformLogicalHeight; } - RenderRegion* mapFromFlowToRegion(TransformState&) const; - - void removeRenderBoxRegionInfo(RenderBox*); - bool logicalWidthChangedInRegionsForBlock(const RenderBlock*); - - LayoutUnit contentLogicalWidthOfFirstRegion() const; - LayoutUnit contentLogicalHeightOfFirstRegion() const; - LayoutUnit contentLogicalLeftOfFirstRegion() const; - RenderRegion* firstRegion() const; RenderRegion* lastRegion() const; - bool previousRegionCountChanged() const { return m_previousRegionCount != m_regionList.size(); } - void updatePreviousRegionCount() { m_previousRegionCount = m_regionList.size(); } - void setRegionRangeForBox(const RenderBox*, LayoutUnit offsetFromLogicalTopOfFirstPage); void getRegionRangeForBox(const RenderBox*, RenderRegion*& startRegion, RenderRegion*& endRegion) const; - void clearRenderObjectCustomStyle(const RenderObject*, - const RenderRegion* oldStartRegion = 0, const RenderRegion* oldEndRegion = 0, - const RenderRegion* newStartRegion = 0, const RenderRegion* newEndRegion = 0); - - // Check if the object is in region and the region is part of this flow thread. - bool objectInFlowRegion(const RenderObject*, const RenderRegion*) const; - - void markAutoLogicalHeightRegionsForLayout(); - - bool addForcedRegionBreak(LayoutUnit, RenderObject* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment = 0); - void applyBreakAfterContent(LayoutUnit); + virtual bool addForcedRegionBreak(LayoutUnit, RenderObject* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment = 0) { return false; } + virtual bool isPageLogicalHeightKnown() const { return true; } bool pageLogicalSizeChanged() const { return m_pageLogicalSizeChanged; } - bool hasAutoLogicalHeightRegions() const { ASSERT(isAutoLogicalHeightRegionsCountConsistent()); return m_autoLogicalHeightRegionsCount; } - void incrementAutoLogicalHeightRegions(); - void decrementAutoLogicalHeightRegions(); - -#ifndef NDEBUG - bool isAutoLogicalHeightRegionsCountConsistent() const; -#endif - void collectLayerFragments(LayerFragments&, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect); LayoutRect fragmentsBoundingBox(const LayoutRect& layerBoundingBox); - void setInConstrainedLayoutPhase(bool value) { m_inConstrainedLayoutPhase = value; } - bool inConstrainedLayoutPhase() const { return m_inConstrainedLayoutPhase; } - - bool needsTwoPhasesLayout() const { return m_needsTwoPhasesLayout; } - void clearNeedsTwoPhasesLayout() { m_needsTwoPhasesLayout = false; } - - void pushFlowThreadLayoutState(const RenderObject*); + void pushFlowThreadLayoutState(const RenderObject&); void popFlowThreadLayoutState(); LayoutUnit offsetFromLogicalTopOfFirstRegion(const RenderBlock*) const; @@ -178,31 +118,8 @@ public: protected: virtual const char* renderName() const = 0; - // Overridden by columns/pages to set up an initial logical width of the page width even when - // no regions have been generated yet. - virtual LayoutUnit initialLogicalWidth() const { return 0; }; - - virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE; - - void updateRegionsFlowThreadPortionRect(const RenderRegion* = 0); + void updateRegionsFlowThreadPortionRect(); bool shouldRepaint(const LayoutRect&) const; - bool regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const; - - LayoutRect computeRegionClippingRect(const LayoutPoint&, const LayoutRect&, const LayoutRect&) const; - - void setDispatchRegionLayoutUpdateEvent(bool value) { m_dispatchRegionLayoutUpdateEvent = value; } - bool shouldDispatchRegionLayoutUpdateEvent() { return m_dispatchRegionLayoutUpdateEvent; } - - void setDispatchRegionOversetChangeEvent(bool value) { m_dispatchRegionOversetChangeEvent = value; } - bool shouldDispatchRegionOversetChangeEvent() const { return m_dispatchRegionOversetChangeEvent; } - - // Override if the flow thread implementation supports dispatching events when the flow layout is updated (e.g. for named flows) - virtual void dispatchRegionLayoutUpdateEvent() { m_dispatchRegionLayoutUpdateEvent = false; } - virtual void dispatchRegionOversetChangeEvent() { m_dispatchRegionOversetChangeEvent = false; } - - void initializeRegionsComputedAutoHeight(RenderRegion* = 0); - - virtual void autoGenerateRegionsToBlockOffset(LayoutUnit) { }; bool cachedOffsetFromLogicalTopOfFirstRegion(const RenderBox*, LayoutUnit&) const; void setOffsetFromLogicalTopOfFirstRegion(const RenderBox*, LayoutUnit); @@ -211,7 +128,6 @@ protected: const RenderBox* currentStatePusherRenderBox() const; RenderRegionList m_regionList; - unsigned short m_previousRegionCount; class RenderRegionRange { public: @@ -265,10 +181,6 @@ protected: typedef HashMap<const RenderBox*, RenderRegionRange> RenderRegionRangeMap; RenderRegionRangeMap m_regionRangeMap; - typedef HashMap<RenderObject*, RenderRegion*> RenderObjectToRegionMap; - RenderObjectToRegionMap m_breakBeforeToRegionMap; - RenderObjectToRegionMap m_breakAfterToRegionMap; - // Stack of objects that pushed a LayoutState object on the RenderView. The // objects on the stack are the ones that are curently in the process of being // laid out. @@ -276,23 +188,11 @@ protected: typedef HashMap<const RenderBox*, LayoutUnit> RenderBoxToOffsetMap; RenderBoxToOffsetMap m_boxesToOffsetMap; - unsigned m_autoLogicalHeightRegionsCount; - RegionIntervalTree m_regionIntervalTree; bool m_regionsInvalidated : 1; - bool m_regionsHaveUniformLogicalWidth : 1; bool m_regionsHaveUniformLogicalHeight : 1; - bool m_hasRegionsWithStyling : 1; - bool m_dispatchRegionLayoutUpdateEvent : 1; - bool m_dispatchRegionOversetChangeEvent : 1; bool m_pageLogicalSizeChanged : 1; - bool m_inConstrainedLayoutPhase : 1; - bool m_needsTwoPhasesLayout : 1; - -private: - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderFlowThread, isRenderFlowThread()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderFrame.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderFrame.cpp index 329ae3422b4..3468cc3af7c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderFrame.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderFrame.cpp @@ -47,21 +47,4 @@ void RenderFrame::updateFromElement() toRenderFrameSet(parent())->notifyFrameEdgeInfoChanged(); } -void RenderFrame::viewCleared() -{ - HTMLFrameElement* element = toHTMLFrameElement(node()); - if (!element || !widget() || !widget()->isFrameView()) - return; - - FrameView* view = toFrameView(widget()); - - int marginWidth = element->marginWidth(); - int marginHeight = element->marginHeight(); - - if (marginWidth != -1) - view->setMarginWidth(marginWidth); - if (marginHeight != -1) - view->setMarginHeight(marginHeight); -} - } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderFrame.h b/chromium/third_party/WebKit/Source/core/rendering/RenderFrame.h index 55391b98bd9..8d953191ad9 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderFrame.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderFrame.h @@ -37,12 +37,10 @@ public: FrameEdgeInfo edgeInfo() const; private: - virtual const char* renderName() const { return "RenderFrame"; } - virtual bool isFrame() const { return true; } + virtual const char* renderName() const OVERRIDE { return "RenderFrame"; } + virtual bool isFrame() const OVERRIDE { return true; } - virtual void updateFromElement(); - - virtual void viewCleared(); + virtual void updateFromElement() OVERRIDE; }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderFrame, isFrame()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderFrameSet.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderFrameSet.cpp index a0bf472cac3..afae324b731 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderFrameSet.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderFrameSet.cpp @@ -26,13 +26,11 @@ #include "core/dom/Document.h" #include "core/events/MouseEvent.h" -#include "core/events/ThreadLocalEventNames.h" +#include "core/frame/LocalFrame.h" #include "core/html/HTMLDimension.h" #include "core/html/HTMLFrameSetElement.h" #include "core/page/EventHandler.h" -#include "core/frame/Frame.h" #include "core/rendering/GraphicsContextAnnotator.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/PaintInfo.h" #include "core/rendering/RenderFrame.h" #include "core/rendering/RenderView.h" @@ -441,13 +439,12 @@ void RenderFrameSet::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); - bool doFullRepaint = !RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && selfNeedsLayout() && checkForRepaintDuringLayout(); + bool doFullRepaint = selfNeedsLayout() && checkForPaintInvalidationDuringLayout(); LayoutRect oldBounds; - RenderLayerModelObject* repaintContainer = 0; + const RenderLayerModelObject* repaintContainer = 0; if (doFullRepaint) { - repaintContainer = containerForRepaint(); - oldBounds = clippedOverflowRectForRepaint(repaintContainer); + repaintContainer = containerForPaintInvalidation(); + oldBounds = boundsRectForPaintInvalidation(repaintContainer); } if (!parent()->isFrameSet() && !document().printing()) { @@ -473,13 +470,13 @@ void RenderFrameSet::layout() computeEdgeInfo(); - updateLayerTransform(); + updateLayerTransformAfterLayout(); if (doFullRepaint) { - repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds)); - LayoutRect newBounds = clippedOverflowRectForRepaint(repaintContainer); + invalidatePaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds), InvalidationSelfLayout); + LayoutRect newBounds = boundsRectForPaintInvalidation(repaintContainer); if (newBounds != oldBounds) - repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds)); + invalidatePaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds), InvalidationSelfLayout); } clearNeedsLayout(); @@ -517,7 +514,7 @@ void RenderFrameSet::positionFrames() if (width != child->width() || height != child->height()) { child->setWidth(width); child->setHeight(height); - child->setNeedsLayout(); + child->setNeedsLayoutAndFullPaintInvalidation(); child->layout(); } @@ -557,7 +554,7 @@ void RenderFrameSet::continueResizing(GridAxis& axis, int position) return; axis.m_deltas[axis.m_splitBeingResized - 1] += delta; axis.m_deltas[axis.m_splitBeingResized] -= delta; - setNeedsLayout(); + setNeedsLayoutAndFullPaintInvalidation(); } bool RenderFrameSet::userResize(MouseEvent* evt) @@ -596,20 +593,10 @@ void RenderFrameSet::setIsResizing(bool isResizing) if (ancestor->isFrameSet()) toRenderFrameSet(ancestor)->m_isChildResizing = isResizing; } - if (Frame* frame = this->frame()) + if (LocalFrame* frame = this->frame()) frame->eventHandler().setResizingFrameSet(isResizing ? frameSet() : 0); } -bool RenderFrameSet::isResizingRow() const -{ - return m_isResizing && m_rows.m_splitBeingResized != noSplit; -} - -bool RenderFrameSet::isResizingColumn() const -{ - return m_isResizing && m_cols.m_splitBeingResized != noSplit; -} - bool RenderFrameSet::canResizeRow(const IntPoint& p) const { int r = hitTestSplit(m_rows, p.y()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderFrameSet.h b/chromium/third_party/WebKit/Source/core/rendering/RenderFrameSet.h index 21f90eac87a..90bf5933792 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderFrameSet.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderFrameSet.h @@ -30,7 +30,6 @@ namespace WebCore { class HTMLDimension; class HTMLFrameSetElement; class MouseEvent; -class RenderFrame; enum FrameEdge { LeftFrameEdge, RightFrameEdge, TopFrameEdge, BottomFrameEdge }; @@ -62,6 +61,10 @@ public: RenderObject* firstChild() const { ASSERT(children() == virtualChildren()); return children()->firstChild(); } RenderObject* lastChild() const { ASSERT(children() == virtualChildren()); return children()->lastChild(); } + // If you have a RenderFrameSet, use firstChild or lastChild instead. + void slowFirstChild() const WTF_DELETED_FUNCTION; + void slowLastChild() const WTF_DELETED_FUNCTION; + const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } @@ -69,9 +72,6 @@ public: bool userResize(MouseEvent*); - bool isResizingRow() const; - bool isResizingColumn() const; - bool canResizeRow(const IntPoint&) const; bool canResizeColumn(const IntPoint&) const; @@ -94,16 +94,16 @@ private: int m_splitResizeOffset; }; - virtual RenderObjectChildList* virtualChildren() { return children(); } - virtual const RenderObjectChildList* virtualChildren() const { return children(); } + virtual RenderObjectChildList* virtualChildren() OVERRIDE { return children(); } + virtual const RenderObjectChildList* virtualChildren() const OVERRIDE { return children(); } - virtual const char* renderName() const { return "RenderFrameSet"; } - virtual bool isFrameSet() const { return true; } + virtual const char* renderName() const OVERRIDE { return "RenderFrameSet"; } + virtual bool isFrameSet() const OVERRIDE { return true; } - virtual void layout(); - virtual void paint(PaintInfo&, const LayoutPoint&); - virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; - virtual CursorDirective getCursor(const LayoutPoint&, Cursor&) const; + virtual void layout() OVERRIDE; + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; + virtual CursorDirective getCursor(const LayoutPoint&, Cursor&) const OVERRIDE; inline HTMLFrameSetElement* frameSet() const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderFullScreen.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderFullScreen.cpp index 23fa9925c0f..9ce9810a3ac 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderFullScreen.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderFullScreen.cpp @@ -39,9 +39,8 @@ public: setDocumentForAnonymous(&owner->document()); } private: - virtual bool isRenderFullScreenPlaceholder() const { return true; } - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - virtual void willBeDestroyed(); + virtual bool isRenderFullScreenPlaceholder() const OVERRIDE { return true; } + virtual void willBeDestroyed() OVERRIDE; RenderFullScreen* m_owner; }; @@ -76,9 +75,9 @@ void RenderFullScreen::willBeDestroyed() // RenderObjects are unretained, so notify the document (which holds a pointer to a RenderFullScreen) // if it's RenderFullScreen is destroyed. - FullscreenElementStack* controller = FullscreenElementStack::from(&document()); - if (controller->fullScreenRenderer() == this) - controller->fullScreenRendererDestroyed(); + FullscreenElementStack& controller = FullscreenElementStack::from(document()); + if (controller.fullScreenRenderer() == this) + controller.fullScreenRendererDestroyed(); RenderFlexibleBox::willBeDestroyed(); } @@ -91,11 +90,11 @@ static PassRefPtr<RenderStyle> createFullScreenStyle() fullscreenStyle->setZIndex(INT_MAX); fullscreenStyle->setFontDescription(FontDescription()); - fullscreenStyle->font().update(0); + fullscreenStyle->font().update(nullptr); fullscreenStyle->setDisplay(FLEX); fullscreenStyle->setJustifyContent(JustifyCenter); - fullscreenStyle->setAlignItems(AlignCenter); + fullscreenStyle->setAlignItems(ItemPositionCenter); fullscreenStyle->setFlexDirection(FlowColumn); fullscreenStyle->setPosition(FixedPosition); @@ -104,13 +103,17 @@ static PassRefPtr<RenderStyle> createFullScreenStyle() fullscreenStyle->setLeft(Length(0, WebCore::Fixed)); fullscreenStyle->setTop(Length(0, WebCore::Fixed)); - fullscreenStyle->setBackgroundColor(Color::black); + fullscreenStyle->setBackgroundColor(StyleColor(Color::black)); return fullscreenStyle.release(); } RenderObject* RenderFullScreen::wrapRenderer(RenderObject* object, RenderObject* parent, Document* document) { + // FIXME: We should not modify the structure of the render tree during + // layout. crbug.com/370459 + DeprecatedDisableModifyRenderTreeStructureAsserts disabler; + RenderFullScreen* fullscreenRenderer = RenderFullScreen::createAnonymous(document); fullscreenRenderer->setStyle(createFullScreenStyle()); if (parent && !parent->isChildAllowed(fullscreenRenderer, fullscreenRenderer->style())) { @@ -133,19 +136,24 @@ RenderObject* RenderFullScreen::wrapRenderer(RenderObject* object, RenderObject* // Always just do a full layout to ensure that line boxes get deleted properly. // Because objects moved from |parent| to |fullscreenRenderer|, we want to // make new line boxes instead of leaving the old ones around. - parent->setNeedsLayoutAndPrefWidthsRecalc(); - containingBlock->setNeedsLayoutAndPrefWidthsRecalc(); + parent->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); + containingBlock->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } fullscreenRenderer->addChild(object); - fullscreenRenderer->setNeedsLayoutAndPrefWidthsRecalc(); + fullscreenRenderer->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } - FullscreenElementStack::from(document)->setFullScreenRenderer(fullscreenRenderer); + ASSERT(document); + FullscreenElementStack::from(*document).setFullScreenRenderer(fullscreenRenderer); return fullscreenRenderer; } void RenderFullScreen::unwrapRenderer() { + // FIXME: We should not modify the structure of the render tree during + // layout. crbug.com/370459 + DeprecatedDisableModifyRenderTreeStructureAsserts disabler; + if (parent()) { RenderObject* child; while ((child = firstChild())) { @@ -156,13 +164,13 @@ void RenderFullScreen::unwrapRenderer() toRenderBox(child)->clearOverrideSize(); child->remove(); parent()->addChild(child, this); - parent()->setNeedsLayoutAndPrefWidthsRecalc(); + parent()->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } } if (placeholder()) placeholder()->remove(); remove(); - FullscreenElementStack::from(&document())->setFullScreenRenderer(0); + FullscreenElementStack::from(document()).setFullScreenRenderer(0); } void RenderFullScreen::setPlaceholder(RenderBlock* placeholder) @@ -182,7 +190,7 @@ void RenderFullScreen::createPlaceholder(PassRefPtr<RenderStyle> style, const La m_placeholder->setStyle(style); if (parent()) { parent()->addChild(m_placeholder, this); - parent()->setNeedsLayoutAndPrefWidthsRecalc(); + parent()->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } } else m_placeholder->setStyle(style); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderFullScreen.h b/chromium/third_party/WebKit/Source/core/rendering/RenderFullScreen.h index 48c40f4f7fe..285dbd21a70 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderFullScreen.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderFullScreen.h @@ -34,8 +34,8 @@ class RenderFullScreen FINAL : public RenderFlexibleBox { public: static RenderFullScreen* createAnonymous(Document*); - virtual bool isRenderFullScreen() const { return true; } - virtual const char* renderName() const { return "RenderFullScreen"; } + virtual bool isRenderFullScreen() const OVERRIDE { return true; } + virtual const char* renderName() const OVERRIDE { return "RenderFullScreen"; } void setPlaceholder(RenderBlock*); RenderBlock* placeholder() { return m_placeholder; } @@ -47,8 +47,7 @@ public: private: RenderFullScreen(); - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - virtual void willBeDestroyed(); + virtual void willBeDestroyed() OVERRIDE; protected: RenderBlock* m_placeholder; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderGeometryMap.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderGeometryMap.cpp index 07ab16f7014..13782a8af3d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderGeometryMap.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderGeometryMap.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "core/rendering/RenderGeometryMap.h" -#include "core/frame/Frame.h" +#include "core/frame/LocalFrame.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderView.h" #include "platform/geometry/TransformState.h" @@ -57,7 +57,7 @@ void RenderGeometryMap::mapToContainer(TransformState& transformState, const Ren } bool inFixed = false; -#if !ASSERT_DISABLED +#if ASSERT_ENABLED bool foundContainer = !container || (m_mapping.size() && m_mapping[0].m_renderer == container); #endif @@ -66,7 +66,7 @@ void RenderGeometryMap::mapToContainer(TransformState& transformState, const Ren // If container is the root RenderView (step 0) we want to apply its fixed position offset. if (i > 0 && currentStep.m_renderer == container) { -#if !ASSERT_DISABLED +#if ASSERT_ENABLED foundContainer = true; #endif break; @@ -109,14 +109,14 @@ FloatPoint RenderGeometryMap::mapToContainer(const FloatPoint& p, const RenderLa FloatPoint result; if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!container || (m_mapping.size() && container == m_mapping[0].m_renderer))) - result = p + roundedIntSize(m_accumulatedOffset); + result = p + m_accumulatedOffset; else { TransformState transformState(TransformState::ApplyTransformDirection, p); mapToContainer(transformState, container); result = transformState.lastPlanarPoint(); } -#if !ASSERT_DISABLED +#if ASSERT_ENABLED if (m_mapping.size() > 0) { const RenderObject* lastRenderer = m_mapping.last().m_renderer; const RenderLayer* layer = lastRenderer->enclosingLayer(); @@ -125,7 +125,7 @@ FloatPoint RenderGeometryMap::mapToContainer(const FloatPoint& p, const RenderLa // therefore not necessarily expected to be correct here. This is ok, // because they will be recomputed if the layer becomes visible. if (!layer || !layer->subtreeIsInvisible()) { - FloatPoint rendererMappedResult = lastRenderer->localToAbsolute(p, m_mapCoordinatesFlags); + FloatPoint rendererMappedResult = lastRenderer->localToContainerPoint(p, container, m_mapCoordinatesFlags); ASSERT(roundedIntPoint(rendererMappedResult) == roundedIntPoint(result)); } @@ -137,7 +137,7 @@ FloatPoint RenderGeometryMap::mapToContainer(const FloatPoint& p, const RenderLa #ifndef NDEBUG // Handy function to call from gdb while debugging mismatched point/rect errors. -void RenderGeometryMap::dumpSteps() +void RenderGeometryMap::dumpSteps() const { fprintf(stderr, "RenderGeometryMap::dumpSteps accumulatedOffset=%d,%d\n", m_accumulatedOffset.width().toInt(), m_accumulatedOffset.height().toInt()); for (int i = m_mapping.size() - 1; i >= 0; --i) { @@ -162,7 +162,7 @@ FloatQuad RenderGeometryMap::mapToContainer(const FloatRect& rect, const RenderL result = transformState.lastPlanarQuad().boundingBox(); } -#if !ASSERT_DISABLED +#if ASSERT_ENABLED if (m_mapping.size() > 0) { const RenderObject* lastRenderer = m_mapping.last().m_renderer; const RenderLayer* layer = lastRenderer->enclosingLayer(); @@ -170,7 +170,7 @@ FloatQuad RenderGeometryMap::mapToContainer(const FloatRect& rect, const RenderL // Bounds for invisible layers are intentionally not calculated, and are // therefore not necessarily expected to be correct here. This is ok, // because they will be recomputed if the layer becomes visible. - if (!layer || !layer->subtreeIsInvisible()) { + if (!layer->subtreeIsInvisible() && lastRenderer->style()->visibility() == VISIBLE) { FloatRect rendererMappedResult = lastRenderer->localToContainerQuad(rect, container, m_mapCoordinatesFlags).boundingBox(); // Inspector creates renderers with negative width <https://bugs.webkit.org/show_bug.cgi?id=87194>. @@ -235,7 +235,8 @@ void RenderGeometryMap::pushMappingsToAncestor(const RenderLayer* layer, const R } TemporaryChange<size_t> positionChange(m_insertionPosition, m_mapping.size()); - push(renderer, toLayoutSize(layerOffset), /*accumulatingTransform*/ true, /*isNonUniform*/ false, /*isFixedPosition*/ false, /*hasTransform*/ false); + bool accumulatingTransform = layer->renderer()->style()->preserves3D() || ancestorLayer->renderer()->style()->preserves3D(); + push(renderer, toLayoutSize(layerOffset), accumulatingTransform, /*isNonUniform*/ false, /*isFixedPosition*/ false, /*hasTransform*/ false); return; } const RenderLayerModelObject* ancestorRenderer = ancestorLayer ? ancestorLayer->renderer() : 0; @@ -328,7 +329,7 @@ void RenderGeometryMap::stepRemoved(const RenderGeometryMapStep& step) } } -#if !ASSERT_DISABLED +#if ASSERT_ENABLED bool RenderGeometryMap::isTopmostRenderView(const RenderObject* renderer) const { if (!renderer->isRenderView()) diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderGeometryMap.h b/chromium/third_party/WebKit/Source/core/rendering/RenderGeometryMap.h index 8049bbbc066..807c458be7e 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderGeometryMap.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderGeometryMap.h @@ -38,7 +38,6 @@ namespace WebCore { class RenderLayer; class RenderLayerModelObject; -class RenderView; class TransformState; // Stores data about how to map from one renderer to its container. @@ -121,10 +120,10 @@ private: bool hasFixedPositionStep() const { return m_fixedStepsCount; } #ifndef NDEBUG - void dumpSteps(); + void dumpSteps() const; #endif -#if !ASSERT_DISABLED +#if ASSERT_ENABLED bool isTopmostRenderView(const RenderObject* renderer) const; #endif @@ -141,10 +140,6 @@ private: } // namespace WebCore -namespace WTF { -// This is required for a struct with OwnPtr. We know RenderGeometryMapStep is simple enough that -// initializing to 0 and moving with memcpy (and then not destructing the original) will work. -template<> struct VectorTraits<WebCore::RenderGeometryMapStep> : SimpleClassVectorTraits { }; -} +WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(WebCore::RenderGeometryMapStep); #endif // RenderGeometryMap_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderGrid.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderGrid.cpp index 38c296ac866..0d167415707 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderGrid.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderGrid.cpp @@ -26,10 +26,12 @@ #include "config.h" #include "core/rendering/RenderGrid.h" +#include "core/rendering/FastTextAutosizer.h" #include "core/rendering/LayoutRepainter.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderView.h" #include "core/rendering/style/GridCoordinate.h" +#include "platform/LengthFunctions.h" namespace WebCore { @@ -75,7 +77,7 @@ struct GridTrackForNormalization { } // Required by std::sort. - GridTrackForNormalization operator=(const GridTrackForNormalization& o) + GridTrackForNormalization& operator=(const GridTrackForNormalization& o) { m_track = o.m_track; m_flex = o.m_flex; @@ -120,16 +122,37 @@ public: return 0; } - PassOwnPtr<GridCoordinate> nextEmptyGridArea() + bool checkEmptyCells(size_t rowSpan, size_t columnSpan) const + { + // Ignore cells outside current grid as we will grow it later if needed. + size_t maxRows = std::min(m_rowIndex + rowSpan, m_grid.size()); + size_t maxColumns = std::min(m_columnIndex + columnSpan, m_grid[0].size()); + + // This adds a O(N^2) behavior that shouldn't be a big deal as we expect spanning areas to be small. + for (size_t row = m_rowIndex; row < maxRows; ++row) { + for (size_t column = m_columnIndex; column < maxColumns; ++column) { + const GridCell& children = m_grid[row][column]; + if (!children.isEmpty()) + return false; + } + } + + return true; + } + + PassOwnPtr<GridCoordinate> nextEmptyGridArea(size_t fixedTrackSpan, size_t varyingTrackSpan) { ASSERT(!m_grid.isEmpty()); + ASSERT(fixedTrackSpan >= 1 && varyingTrackSpan >= 1); + + size_t rowSpan = (m_direction == ForColumns) ? varyingTrackSpan : fixedTrackSpan; + size_t columnSpan = (m_direction == ForColumns) ? fixedTrackSpan : varyingTrackSpan; size_t& varyingTrackIndex = (m_direction == ForColumns) ? m_rowIndex : m_columnIndex; const size_t endOfVaryingTrackIndex = (m_direction == ForColumns) ? m_grid.size() : m_grid[0].size(); for (; varyingTrackIndex < endOfVaryingTrackIndex; ++varyingTrackIndex) { - const GridCell& children = m_grid[m_rowIndex][m_columnIndex]; - if (children.isEmpty()) { - OwnPtr<GridCoordinate> result = adoptPtr(new GridCoordinate(GridSpan(m_rowIndex, m_rowIndex), GridSpan(m_columnIndex, m_columnIndex))); + if (checkEmptyCells(rowSpan, columnSpan)) { + OwnPtr<GridCoordinate> result = adoptPtr(new GridCoordinate(GridSpan(m_rowIndex, m_rowIndex + rowSpan - 1), GridSpan(m_columnIndex, m_columnIndex + columnSpan - 1))); // Advance the iterator to avoid an infinite loop where we would return the same grid area over and over. ++varyingTrackIndex; return result.release(); @@ -168,7 +191,6 @@ RenderGrid::RenderGrid(Element* element) : RenderBlock(element) , m_gridIsDirty(true) , m_orderIterator(this) - , m_gridItemOverflowGridArea(false) { // All of our children must be block level. setChildrenInline(false); @@ -190,20 +212,44 @@ void RenderGrid::addChild(RenderObject* newChild, RenderObject* beforeChild) return; } + if (style()->gridAutoFlow() != AutoFlowNone) { + // The grid needs to be recomputed as it might contain auto-placed items that will change their position. + dirtyGrid(); + return; + } + RenderBox* newChildBox = toRenderBox(newChild); - OwnPtr<GridSpan> rowPositions = resolveGridPositionsFromStyle(newChildBox, ForRows); - OwnPtr<GridSpan> columnPositions = resolveGridPositionsFromStyle(newChildBox, ForColumns); + OwnPtr<GridSpan> rowPositions = GridResolvedPosition::resolveGridPositionsFromStyle(*style(), *newChildBox, ForRows); + OwnPtr<GridSpan> columnPositions = GridResolvedPosition::resolveGridPositionsFromStyle(*style(), *newChildBox, ForColumns); if (!rowPositions || !columnPositions) { // The new child requires the auto-placement algorithm to run so we need to recompute the grid fully. dirtyGrid(); + return; } else { - if (gridRowCount() <= rowPositions->finalPositionIndex || gridColumnCount() <= columnPositions->finalPositionIndex) { - // FIXME: We could just insert the new child provided we had a primitive to arbitrarily grow the grid. - dirtyGrid(); - } else { - insertItemIntoGrid(newChildBox, GridCoordinate(*rowPositions, *columnPositions)); - } + insertItemIntoGrid(newChildBox, GridCoordinate(*rowPositions, *columnPositions)); + addChildToIndexesMap(newChildBox); + } +} + +void RenderGrid::addChildToIndexesMap(RenderBox* child) +{ + ASSERT(!m_gridItemsIndexesMap.contains(child)); + RenderBox* sibling = child->nextSiblingBox(); + bool lastSibling = !sibling; + + if (lastSibling) + sibling = child->previousSiblingBox(); + + size_t index = 0; + if (sibling) + index = lastSibling ? m_gridItemsIndexesMap.get(sibling) + 1 : m_gridItemsIndexesMap.get(sibling); + + if (sibling && !lastSibling) { + for (; sibling; sibling = sibling->nextSiblingBox()) + m_gridItemsIndexesMap.set(sibling, m_gridItemsIndexesMap.get(sibling) + 1); } + + m_gridItemsIndexesMap.set(child, index); } void RenderGrid::removeChild(RenderObject* child) @@ -214,8 +260,24 @@ void RenderGrid::removeChild(RenderObject* child) return; ASSERT(child->isBox()); - // FIXME: We could avoid dirtying the grid in some cases (e.g. if it's an explicitly positioned element). - dirtyGrid(); + + if (style()->gridAutoFlow() != AutoFlowNone) { + // The grid needs to be recomputed as it might contain auto-placed items that will change their position. + dirtyGrid(); + return; + } + + const RenderBox* childBox = toRenderBox(child); + GridCoordinate coordinate = m_gridItemCoordinate.take(childBox); + + for (GridSpan::iterator row = coordinate.rows.begin(); row != coordinate.rows.end(); ++row) { + for (GridSpan::iterator column = coordinate.columns.begin(); column != coordinate.columns.end(); ++column) { + GridCell& cell = m_grid[row.toInt()][column.toInt()]; + cell.remove(cell.find(childBox)); + } + } + + m_gridItemsIndexesMap.remove(childBox); } void RenderGrid::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) @@ -237,8 +299,8 @@ void RenderGrid::styleDidChange(StyleDifference diff, const RenderStyle* oldStyl bool RenderGrid::explicitGridDidResize(const RenderStyle* oldStyle) const { - return oldStyle->gridDefinitionColumns().size() != style()->gridDefinitionColumns().size() - || oldStyle->gridDefinitionRows().size() != style()->gridDefinitionRows().size(); + return oldStyle->gridTemplateColumns().size() != style()->gridTemplateColumns().size() + || oldStyle->gridTemplateRows().size() != style()->gridTemplateRows().size(); } bool RenderGrid::namedGridLinesDefinitionDidChange(const RenderStyle* oldStyle) const @@ -247,7 +309,7 @@ bool RenderGrid::namedGridLinesDefinitionDidChange(const RenderStyle* oldStyle) || oldStyle->namedGridColumnLines() != style()->namedGridColumnLines(); } -void RenderGrid::layoutBlock(bool relayoutChildren, LayoutUnit) +void RenderGrid::layoutBlock(bool relayoutChildren) { ASSERT(needsLayout()); @@ -256,21 +318,16 @@ void RenderGrid::layoutBlock(bool relayoutChildren, LayoutUnit) // FIXME: Much of this method is boiler plate that matches RenderBox::layoutBlock and Render*FlexibleBox::layoutBlock. // It would be nice to refactor some of the duplicate code. - LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); - LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode()); - - // Regions changing widths can force us to relayout our children. - RenderFlowThread* flowThread = flowThreadContainingBlock(); - if (logicalWidthChangedInRegions(flowThread)) - relayoutChildren = true; - if (updateRegionsAndShapesLogicalSize(flowThread)) - relayoutChildren = true; + LayoutRepainter repainter(*this, checkForPaintInvalidationDuringLayout()); + LayoutState state(*this, locationOffset()); LayoutSize previousSize = size(); setLogicalHeight(0); updateLogicalWidth(); + FastTextAutosizer::LayoutScope fastTextAutosizerLayoutScope(this); + layoutGridItems(); LayoutUnit oldClientAfterEdge = clientLogicalBottom(); @@ -279,14 +336,13 @@ void RenderGrid::layoutBlock(bool relayoutChildren, LayoutUnit) if (size() != previousSize) relayoutChildren = true; - layoutPositionedObjects(relayoutChildren || isRoot()); + layoutPositionedObjects(relayoutChildren || isDocumentElement()); - computeRegionRangeForBlock(flowThread); + computeRegionRangeForBlock(flowThreadContainingBlock()); computeOverflow(oldClientAfterEdge); - statePusher.pop(); - updateLayerTransform(); + updateLayerTransformAfterLayout(); // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if // we overflow or not. @@ -304,7 +360,7 @@ void RenderGrid::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, Layo GridSizingData sizingData(gridColumnCount(), gridRowCount()); LayoutUnit availableLogicalSpace = 0; - const_cast<RenderGrid*>(this)->computedUsedBreadthOfGridTracks(ForColumns, sizingData, availableLogicalSpace); + const_cast<RenderGrid*>(this)->computeUsedBreadthOfGridTracks(ForColumns, sizingData, availableLogicalSpace); for (size_t i = 0; i < sizingData.columnTracks.size(); ++i) { LayoutUnit minTrackBreadth = sizingData.columnTracks[i].m_usedBreadth; @@ -337,16 +393,24 @@ void RenderGrid::computePreferredLogicalWidths() clearPreferredLogicalWidthsDirty(); } -void RenderGrid::computedUsedBreadthOfGridTracks(GridTrackSizingDirection direction, GridSizingData& sizingData) +void RenderGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection direction, GridSizingData& sizingData) { LayoutUnit availableLogicalSpace = (direction == ForColumns) ? availableLogicalWidth() : availableLogicalHeight(IncludeMarginBorderPadding); - computedUsedBreadthOfGridTracks(direction, sizingData, availableLogicalSpace); + computeUsedBreadthOfGridTracks(direction, sizingData, availableLogicalSpace); } -void RenderGrid::computedUsedBreadthOfGridTracks(GridTrackSizingDirection direction, GridSizingData& sizingData, LayoutUnit& availableLogicalSpace) +bool RenderGrid::gridElementIsShrinkToFit() +{ + return isFloatingOrOutOfFlowPositioned(); +} + +void RenderGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection direction, GridSizingData& sizingData, LayoutUnit& availableLogicalSpace) { Vector<GridTrack>& tracks = (direction == ForColumns) ? sizingData.columnTracks : sizingData.rowTracks; + Vector<size_t> flexibleSizedTracksIndex; sizingData.contentSizedTracksIndex.shrink(0); + + // 1. Initialize per Grid track variables. for (size_t i = 0; i < tracks.size(); ++i) { GridTrack& track = tracks[i]; const GridTrackSize& trackSize = gridTrackSize(direction, i); @@ -360,8 +424,11 @@ void RenderGrid::computedUsedBreadthOfGridTracks(GridTrackSizingDirection direct if (trackSize.isContentSized()) sizingData.contentSizedTracksIndex.append(i); + if (trackSize.maxTrackBreadth().isFlex()) + flexibleSizedTracksIndex.append(i); } + // 2. Resolve content-based TrackSizingFunctions. if (!sizingData.contentSizedTracksIndex.isEmpty()) resolveContentBasedTrackSizingFunctions(direction, sizingData, availableLogicalSpace); @@ -370,26 +437,60 @@ void RenderGrid::computedUsedBreadthOfGridTracks(GridTrackSizingDirection direct availableLogicalSpace -= tracks[i].m_usedBreadth; } - if (availableLogicalSpace <= 0) + const bool hasUndefinedRemainingSpace = (direction == ForRows) ? style()->logicalHeight().isAuto() : gridElementIsShrinkToFit(); + + if (!hasUndefinedRemainingSpace && availableLogicalSpace <= 0) return; + // 3. Grow all Grid tracks in GridTracks from their UsedBreadth up to their MaxBreadth value until + // availableLogicalSpace (RemainingSpace in the specs) is exhausted. const size_t tracksSize = tracks.size(); - Vector<GridTrack*> tracksForDistribution(tracksSize); - for (size_t i = 0; i < tracksSize; ++i) - tracksForDistribution[i] = tracks.data() + i; + if (!hasUndefinedRemainingSpace) { + Vector<GridTrack*> tracksForDistribution(tracksSize); + for (size_t i = 0; i < tracksSize; ++i) + tracksForDistribution[i] = tracks.data() + i; - distributeSpaceToTracks(tracksForDistribution, 0, &GridTrack::usedBreadth, &GridTrack::growUsedBreadth, sizingData, availableLogicalSpace); + distributeSpaceToTracks(tracksForDistribution, 0, &GridTrack::usedBreadth, &GridTrack::growUsedBreadth, sizingData, availableLogicalSpace); + } else { + for (size_t i = 0; i < tracksSize; ++i) + tracks[i].m_usedBreadth = tracks[i].m_maxBreadth; + } + + if (flexibleSizedTracksIndex.isEmpty()) + return; // 4. Grow all Grid tracks having a fraction as the MaxTrackSizingFunction. + double normalizedFractionBreadth = 0; + if (!hasUndefinedRemainingSpace) { + normalizedFractionBreadth = computeNormalizedFractionBreadth(tracks, GridSpan(0, tracks.size() - 1), direction, availableLogicalSpace); + } else { + for (size_t i = 0; i < flexibleSizedTracksIndex.size(); ++i) { + const size_t trackIndex = flexibleSizedTracksIndex[i]; + const GridTrackSize& trackSize = gridTrackSize(direction, trackIndex); + normalizedFractionBreadth = std::max(normalizedFractionBreadth, tracks[trackIndex].m_usedBreadth / trackSize.maxTrackBreadth().flex()); + } - // FIXME: Handle the case where RemainingSpace is not defined. - double normalizedFractionBreadth = computeNormalizedFractionBreadth(tracks, direction, availableLogicalSpace); - for (size_t i = 0; i < tracksSize; ++i) { - const GridTrackSize& trackSize = gridTrackSize(direction, i); - if (!trackSize.maxTrackBreadth().isFlex()) - continue; + for (size_t i = 0; i < flexibleSizedTracksIndex.size(); ++i) { + GridIterator iterator(m_grid, direction, flexibleSizedTracksIndex[i]); + while (RenderBox* gridItem = iterator.nextGridItem()) { + const GridCoordinate coordinate = cachedGridCoordinate(gridItem); + const GridSpan span = (direction == ForColumns) ? coordinate.columns : coordinate.rows; + + // Do not include already processed items. + if (i > 0 && span.resolvedInitialPosition.toInt() <= flexibleSizedTracksIndex[i - 1]) + continue; + + double itemNormalizedFlexBreadth = computeNormalizedFractionBreadth(tracks, span, direction, maxContentForChild(gridItem, direction, sizingData.columnTracks)); + normalizedFractionBreadth = std::max(normalizedFractionBreadth, itemNormalizedFlexBreadth); + } + } + } - tracks[i].m_usedBreadth = std::max<LayoutUnit>(tracks[i].m_usedBreadth, normalizedFractionBreadth * trackSize.maxTrackBreadth().flex()); + for (size_t i = 0; i < flexibleSizedTracksIndex.size(); ++i) { + const size_t trackIndex = flexibleSizedTracksIndex[i]; + const GridTrackSize& trackSize = gridTrackSize(direction, trackIndex); + + tracks[trackIndex].m_usedBreadth = std::max<LayoutUnit>(tracks[trackIndex].m_usedBreadth, normalizedFractionBreadth * trackSize.maxTrackBreadth().flex()); } } @@ -428,7 +529,7 @@ LayoutUnit RenderGrid::computeUsedBreadthOfSpecifiedLength(GridTrackSizingDirect { ASSERT(trackLength.isSpecified()); // FIXME: The -1 here should be replaced by whatever the intrinsic height of the grid is. - return valueForLength(trackLength, direction == ForColumns ? logicalWidth() : computeContentLogicalHeight(style()->logicalHeight(), -1), view()); + return valueForLength(trackLength, direction == ForColumns ? logicalWidth() : computeContentLogicalHeight(style()->logicalHeight(), -1)); } static bool sortByGridNormalizedFlexValue(const GridTrackForNormalization& track1, const GridTrackForNormalization& track2) @@ -436,22 +537,21 @@ static bool sortByGridNormalizedFlexValue(const GridTrackForNormalization& track return track1.m_normalizedFlexValue < track2.m_normalizedFlexValue; } -double RenderGrid::computeNormalizedFractionBreadth(Vector<GridTrack>& tracks, GridTrackSizingDirection direction, LayoutUnit availableLogicalSpace) const +double RenderGrid::computeNormalizedFractionBreadth(Vector<GridTrack>& tracks, const GridSpan& tracksSpan, GridTrackSizingDirection direction, LayoutUnit availableLogicalSpace) const { // |availableLogicalSpace| already accounts for the used breadths so no need to remove it here. Vector<GridTrackForNormalization> tracksForNormalization; - for (size_t i = 0; i < tracks.size(); ++i) { - const GridTrackSize& trackSize = gridTrackSize(direction, i); + for (GridSpan::iterator resolvedPosition = tracksSpan.begin(); resolvedPosition != tracksSpan.end(); ++resolvedPosition) { + const GridTrackSize& trackSize = gridTrackSize(direction, resolvedPosition.toInt()); if (!trackSize.maxTrackBreadth().isFlex()) continue; - tracksForNormalization.append(GridTrackForNormalization(tracks[i], trackSize.maxTrackBreadth().flex())); + tracksForNormalization.append(GridTrackForNormalization(tracks[resolvedPosition.toInt()], trackSize.maxTrackBreadth().flex())); } - // FIXME: Ideally we shouldn't come here without any <flex> grid track. - if (tracksForNormalization.isEmpty()) - return LayoutUnit(); + // The function is not called if we don't have <flex> grid tracks + ASSERT(!tracksForNormalization.isEmpty()); std::sort(tracksForNormalization.begin(), tracksForNormalization.end(), sortByGridNormalizedFlexValue); @@ -483,40 +583,37 @@ double RenderGrid::computeNormalizedFractionBreadth(Vector<GridTrack>& tracks, G const GridTrackSize& RenderGrid::gridTrackSize(GridTrackSizingDirection direction, size_t i) const { - const Vector<GridTrackSize>& trackStyles = (direction == ForColumns) ? style()->gridDefinitionColumns() : style()->gridDefinitionRows(); + const Vector<GridTrackSize>& trackStyles = (direction == ForColumns) ? style()->gridTemplateColumns() : style()->gridTemplateRows(); if (i >= trackStyles.size()) return (direction == ForColumns) ? style()->gridAutoColumns() : style()->gridAutoRows(); - return trackStyles[i]; -} - -size_t RenderGrid::explicitGridColumnCount() const -{ - return style()->gridDefinitionColumns().size(); -} - -size_t RenderGrid::explicitGridRowCount() const -{ - return style()->gridDefinitionRows().size(); -} + const GridTrackSize& trackSize = trackStyles[i]; + // If the logical width/height of the grid container is indefinite, percentage values are treated as <auto>. + if (trackSize.isPercentage()) { + Length logicalSize = direction == ForColumns ? style()->logicalWidth() : style()->logicalHeight(); + if (logicalSize.isIntrinsicOrAuto()) { + DEFINE_STATIC_LOCAL(GridTrackSize, autoTrackSize, (Length(Auto))); + return autoTrackSize; + } + } -size_t RenderGrid::explicitGridSizeForSide(GridPositionSide side) const -{ - return (side == ColumnStartSide || side == ColumnEndSide) ? explicitGridColumnCount() : explicitGridRowCount(); + return trackSize; } -LayoutUnit RenderGrid::logicalContentHeightForChild(RenderBox* child, Vector<GridTrack>& columnTracks) +LayoutUnit RenderGrid::logicalHeightForChild(RenderBox* child, Vector<GridTrack>& columnTracks) { - SubtreeLayoutScope layoutScope(child); - if (child->style()->logicalHeight().isPercent()) + SubtreeLayoutScope layoutScope(*child); + LayoutUnit oldOverrideContainingBlockContentLogicalWidth = child->hasOverrideContainingBlockLogicalWidth() ? child->overrideContainingBlockContentLogicalWidth() : LayoutUnit(); + LayoutUnit overrideContainingBlockContentLogicalWidth = gridAreaBreadthForChild(child, ForColumns, columnTracks); + if (child->style()->logicalHeight().isPercent() || oldOverrideContainingBlockContentLogicalWidth != overrideContainingBlockContentLogicalWidth) layoutScope.setNeedsLayout(child); - child->setOverrideContainingBlockContentLogicalWidth(gridAreaBreadthForChild(child, ForColumns, columnTracks)); + child->setOverrideContainingBlockContentLogicalWidth(overrideContainingBlockContentLogicalWidth); // If |child| has a percentage logical height, we shouldn't let it override its intrinsic height, which is // what we are interested in here. Thus we need to set the override logical height to -1 (no possible resolution). child->setOverrideContainingBlockContentLogicalHeight(-1); child->layoutIfNeeded(); - return child->logicalHeight(); + return child->logicalHeight() + child->marginLogicalHeight(); } LayoutUnit RenderGrid::minContentForChild(RenderBox* child, GridTrackSizingDirection direction, Vector<GridTrack>& columnTracks) @@ -532,7 +629,7 @@ LayoutUnit RenderGrid::minContentForChild(RenderBox* child, GridTrackSizingDirec return child->minPreferredLogicalWidth() + marginIntrinsicLogicalWidthForChild(child); } - return logicalContentHeightForChild(child, columnTracks); + return logicalHeightForChild(child, columnTracks); } LayoutUnit RenderGrid::maxContentForChild(RenderBox* child, GridTrackSizingDirection direction, Vector<GridTrack>& columnTracks) @@ -548,7 +645,7 @@ LayoutUnit RenderGrid::maxContentForChild(RenderBox* child, GridTrackSizingDirec return child->maxPreferredLogicalWidth() + marginIntrinsicLogicalWidthForChild(child); } - return logicalContentHeightForChild(child, columnTracks); + return logicalHeightForChild(child, columnTracks); } void RenderGrid::resolveContentBasedTrackSizingFunctions(GridTrackSizingDirection direction, GridSizingData& sizingData, LayoutUnit& availableLogicalSpace) @@ -575,16 +672,16 @@ void RenderGrid::resolveContentBasedTrackSizingFunctions(GridTrackSizingDirectio void RenderGrid::resolveContentBasedTrackSizingFunctionsForItems(GridTrackSizingDirection direction, GridSizingData& sizingData, RenderBox* gridItem, FilterFunction filterFunction, SizingFunction sizingFunction, AccumulatorGetter trackGetter, AccumulatorGrowFunction trackGrowthFunction) { const GridCoordinate coordinate = cachedGridCoordinate(gridItem); - const size_t initialTrackIndex = (direction == ForColumns) ? coordinate.columns.initialPositionIndex : coordinate.rows.initialPositionIndex; - const size_t finalTrackIndex = (direction == ForColumns) ? coordinate.columns.finalPositionIndex : coordinate.rows.finalPositionIndex; + const GridResolvedPosition initialTrackPosition = (direction == ForColumns) ? coordinate.columns.resolvedInitialPosition : coordinate.rows.resolvedInitialPosition; + const GridResolvedPosition finalTrackPosition = (direction == ForColumns) ? coordinate.columns.resolvedFinalPosition : coordinate.rows.resolvedFinalPosition; sizingData.filteredTracks.shrink(0); - for (size_t trackIndex = initialTrackIndex; trackIndex <= finalTrackIndex; ++trackIndex) { - const GridTrackSize& trackSize = gridTrackSize(direction, trackIndex); + for (GridResolvedPosition trackPosition = initialTrackPosition; trackPosition <= finalTrackPosition; ++trackPosition) { + const GridTrackSize& trackSize = gridTrackSize(direction, trackPosition.toInt()); if (!(trackSize.*filterFunction)()) continue; - GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[trackIndex] : sizingData.rowTracks[trackIndex]; + GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[trackPosition.toInt()] : sizingData.rowTracks[trackPosition.toInt()]; sizingData.filteredTracks.append(&track); } @@ -592,8 +689,8 @@ void RenderGrid::resolveContentBasedTrackSizingFunctionsForItems(GridTrackSizing return; LayoutUnit additionalBreadthSpace = (this->*sizingFunction)(gridItem, direction, sizingData.columnTracks); - for (size_t trackIndexForSpace = initialTrackIndex; trackIndexForSpace <= finalTrackIndex; ++trackIndexForSpace) { - GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[trackIndexForSpace] : sizingData.rowTracks[trackIndexForSpace]; + for (GridResolvedPosition trackIndexForSpace = initialTrackPosition; trackIndexForSpace <= finalTrackPosition; ++trackIndexForSpace) { + GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[trackIndexForSpace.toInt()] : sizingData.rowTracks[trackIndexForSpace.toInt()]; additionalBreadthSpace -= (track.*trackGetter)(); } @@ -655,36 +752,33 @@ bool RenderGrid::tracksAreWiderThanMinTrackBreadth(GridTrackSizingDirection dire } #endif -void RenderGrid::growGrid(GridTrackSizingDirection direction) +void RenderGrid::ensureGridSize(size_t maximumRowIndex, size_t maximumColumnIndex) { - if (direction == ForColumns) { - const size_t oldColumnSize = m_grid[0].size(); - for (size_t row = 0; row < m_grid.size(); ++row) - m_grid[row].grow(oldColumnSize + 1); - } else { - const size_t oldRowSize = m_grid.size(); - m_grid.grow(oldRowSize + 1); - m_grid[oldRowSize].grow(m_grid[0].size()); + const size_t oldRowSize = gridRowCount(); + if (maximumRowIndex >= oldRowSize) { + m_grid.grow(maximumRowIndex + 1); + for (size_t row = oldRowSize; row < gridRowCount(); ++row) + m_grid[row].grow(gridColumnCount()); + } + + if (maximumColumnIndex >= gridColumnCount()) { + for (size_t row = 0; row < gridRowCount(); ++row) + m_grid[row].grow(maximumColumnIndex + 1); } } void RenderGrid::insertItemIntoGrid(RenderBox* child, const GridCoordinate& coordinate) { - for (size_t row = coordinate.rows.initialPositionIndex; row <= coordinate.rows.finalPositionIndex; ++row) { - for (size_t column = coordinate.columns.initialPositionIndex; column <= coordinate.columns.finalPositionIndex; ++column) - m_grid[row][column].append(child); + ensureGridSize(coordinate.rows.resolvedFinalPosition.toInt(), coordinate.columns.resolvedFinalPosition.toInt()); + + for (GridSpan::iterator row = coordinate.rows.begin(); row != coordinate.rows.end(); ++row) { + for (GridSpan::iterator column = coordinate.columns.begin(); column != coordinate.columns.end(); ++column) + m_grid[row.toInt()][column.toInt()].append(child); } m_gridItemCoordinate.set(child, coordinate); } -void RenderGrid::insertItemIntoGrid(RenderBox* child, size_t rowTrack, size_t columnTrack) -{ - const GridSpan& rowSpan = resolveGridPositionsFromAutoPlacementPosition(child, ForRows, rowTrack); - const GridSpan& columnSpan = resolveGridPositionsFromAutoPlacementPosition(child, ForColumns, columnTrack); - insertItemIntoGrid(child, GridCoordinate(rowSpan, columnSpan)); -} - void RenderGrid::placeItemsOnGrid() { if (!gridIsDirty()) @@ -704,8 +798,8 @@ void RenderGrid::placeItemsOnGrid() for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) { // FIXME: We never re-resolve positions if the grid is grown during auto-placement which may lead auto / <integer> // positions to not match the author's intent. The specification is unclear on what should be done in this case. - OwnPtr<GridSpan> rowPositions = resolveGridPositionsFromStyle(child, ForRows); - OwnPtr<GridSpan> columnPositions = resolveGridPositionsFromStyle(child, ForColumns); + OwnPtr<GridSpan> rowPositions = GridResolvedPosition::resolveGridPositionsFromStyle(*style(), *child, ForRows); + OwnPtr<GridSpan> columnPositions = GridResolvedPosition::resolveGridPositionsFromStyle(*style(), *child, ForColumns); if (!rowPositions || !columnPositions) { GridSpan* majorAxisPositions = (autoPlacementMajorAxisDirection() == ForColumns) ? columnPositions.get() : rowPositions.get(); if (!majorAxisPositions) @@ -717,8 +811,8 @@ void RenderGrid::placeItemsOnGrid() insertItemIntoGrid(child, GridCoordinate(*rowPositions, *columnPositions)); } - ASSERT(gridRowCount() >= style()->gridDefinitionRows().size()); - ASSERT(gridColumnCount() >= style()->gridDefinitionColumns().size()); + ASSERT(gridRowCount() >= style()->gridTemplateRows().size()); + ASSERT(gridColumnCount() >= style()->gridTemplateColumns().size()); if (autoFlow == AutoFlowNone) { // If we did collect some grid items, they won't be placed thus never laid out. @@ -737,22 +831,35 @@ void RenderGrid::populateExplicitGridAndOrderIterator() { OrderIteratorPopulator populator(m_orderIterator); - size_t maximumRowIndex = std::max<size_t>(1, explicitGridRowCount()); - size_t maximumColumnIndex = std::max<size_t>(1, explicitGridColumnCount()); + size_t maximumRowIndex = std::max<size_t>(1, GridResolvedPosition::explicitGridRowCount(*style())); + size_t maximumColumnIndex = std::max<size_t>(1, GridResolvedPosition::explicitGridColumnCount(*style())); + ASSERT(m_gridItemsIndexesMap.isEmpty()); + size_t childIndex = 0; for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { populator.collectChild(child); + m_gridItemsIndexesMap.set(child, childIndex++); // This function bypasses the cache (cachedGridCoordinate()) as it is used to build it. - OwnPtr<GridSpan> rowPositions = resolveGridPositionsFromStyle(child, ForRows); - OwnPtr<GridSpan> columnPositions = resolveGridPositionsFromStyle(child, ForColumns); - - // |positions| is 0 if we need to run the auto-placement algorithm. Our estimation ignores - // this case as the auto-placement algorithm will grow the grid as needed. - if (rowPositions) - maximumRowIndex = std::max(maximumRowIndex, rowPositions->finalPositionIndex + 1); - if (columnPositions) - maximumColumnIndex = std::max(maximumColumnIndex, columnPositions->finalPositionIndex + 1); + OwnPtr<GridSpan> rowPositions = GridResolvedPosition::resolveGridPositionsFromStyle(*style(), *child, ForRows); + OwnPtr<GridSpan> columnPositions = GridResolvedPosition::resolveGridPositionsFromStyle(*style(), *child, ForColumns); + + // |positions| is 0 if we need to run the auto-placement algorithm. + if (rowPositions) { + maximumRowIndex = std::max<size_t>(maximumRowIndex, rowPositions->resolvedFinalPosition.next().toInt()); + } else { + // Grow the grid for items with a definite row span, getting the largest such span. + GridSpan positions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *child, ForRows, GridResolvedPosition(0)); + maximumRowIndex = std::max<size_t>(maximumRowIndex, positions.resolvedFinalPosition.next().toInt()); + } + + if (columnPositions) { + maximumColumnIndex = std::max<size_t>(maximumColumnIndex, columnPositions->resolvedFinalPosition.next().toInt()); + } else { + // Grow the grid for items with a definite column span, getting the largest such span. + GridSpan positions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *child, ForColumns, GridResolvedPosition(0)); + maximumColumnIndex = std::max<size_t>(maximumColumnIndex, positions.resolvedFinalPosition.next().toInt()); + } } m_grid.grow(maximumRowIndex); @@ -760,20 +867,25 @@ void RenderGrid::populateExplicitGridAndOrderIterator() m_grid[i].grow(maximumColumnIndex); } +PassOwnPtr<GridCoordinate> RenderGrid::createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(const RenderBox* gridItem, GridTrackSizingDirection specifiedDirection, const GridSpan& specifiedPositions) const +{ + GridTrackSizingDirection crossDirection = specifiedDirection == ForColumns ? ForRows : ForColumns; + const size_t endOfCrossDirection = crossDirection == ForColumns ? gridColumnCount() : gridRowCount(); + GridSpan crossDirectionPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *gridItem, crossDirection, GridResolvedPosition(endOfCrossDirection)); + return adoptPtr(new GridCoordinate(specifiedDirection == ForColumns ? crossDirectionPositions : specifiedPositions, specifiedDirection == ForColumns ? specifiedPositions : crossDirectionPositions)); +} + void RenderGrid::placeSpecifiedMajorAxisItemsOnGrid(const Vector<RenderBox*>& autoGridItems) { for (size_t i = 0; i < autoGridItems.size(); ++i) { - OwnPtr<GridSpan> majorAxisPositions = resolveGridPositionsFromStyle(autoGridItems[i], autoPlacementMajorAxisDirection()); - GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), majorAxisPositions->initialPositionIndex); - if (OwnPtr<GridCoordinate> emptyGridArea = iterator.nextEmptyGridArea()) { - insertItemIntoGrid(autoGridItems[i], emptyGridArea->rows.initialPositionIndex, emptyGridArea->columns.initialPositionIndex); - continue; - } - - growGrid(autoPlacementMinorAxisDirection()); - OwnPtr<GridCoordinate> emptyGridArea = iterator.nextEmptyGridArea(); - ASSERT(emptyGridArea); - insertItemIntoGrid(autoGridItems[i], emptyGridArea->rows.initialPositionIndex, emptyGridArea->columns.initialPositionIndex); + OwnPtr<GridSpan> majorAxisPositions = GridResolvedPosition::resolveGridPositionsFromStyle(*style(), *autoGridItems[i], autoPlacementMajorAxisDirection()); + GridSpan minorAxisPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *autoGridItems[i], autoPlacementMinorAxisDirection(), GridResolvedPosition(0)); + + GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), majorAxisPositions->resolvedInitialPosition.toInt()); + OwnPtr<GridCoordinate> emptyGridArea = iterator.nextEmptyGridArea(majorAxisPositions->integerSpan(), minorAxisPositions.integerSpan()); + if (!emptyGridArea) + emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(autoGridItems[i], autoPlacementMajorAxisDirection(), *majorAxisPositions); + insertItemIntoGrid(autoGridItems[i], *emptyGridArea); } } @@ -785,32 +897,41 @@ void RenderGrid::placeAutoMajorAxisItemsOnGrid(const Vector<RenderBox*>& autoGri void RenderGrid::placeAutoMajorAxisItemOnGrid(RenderBox* gridItem) { - OwnPtr<GridSpan> minorAxisPositions = resolveGridPositionsFromStyle(gridItem, autoPlacementMinorAxisDirection()); - ASSERT(!resolveGridPositionsFromStyle(gridItem, autoPlacementMajorAxisDirection())); - size_t minorAxisIndex = 0; + OwnPtr<GridSpan> minorAxisPositions = GridResolvedPosition::resolveGridPositionsFromStyle(*style(), *gridItem, autoPlacementMinorAxisDirection()); + ASSERT(!GridResolvedPosition::resolveGridPositionsFromStyle(*style(), *gridItem, autoPlacementMajorAxisDirection())); + GridSpan majorAxisPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *gridItem, autoPlacementMajorAxisDirection(), GridResolvedPosition(0)); + OwnPtr<GridCoordinate> emptyGridArea; if (minorAxisPositions) { - minorAxisIndex = minorAxisPositions->initialPositionIndex; - GridIterator iterator(m_grid, autoPlacementMinorAxisDirection(), minorAxisIndex); - if (OwnPtr<GridCoordinate> emptyGridArea = iterator.nextEmptyGridArea()) { - insertItemIntoGrid(gridItem, emptyGridArea->rows.initialPositionIndex, emptyGridArea->columns.initialPositionIndex); - return; - } + GridIterator iterator(m_grid, autoPlacementMinorAxisDirection(), minorAxisPositions->resolvedInitialPosition.toInt()); + emptyGridArea = iterator.nextEmptyGridArea(minorAxisPositions->integerSpan(), majorAxisPositions.integerSpan()); + if (!emptyGridArea) + emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(gridItem, autoPlacementMinorAxisDirection(), *minorAxisPositions); } else { + GridSpan minorAxisPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *gridItem, autoPlacementMinorAxisDirection(), GridResolvedPosition(0)); + const size_t endOfMajorAxis = (autoPlacementMajorAxisDirection() == ForColumns) ? gridColumnCount() : gridRowCount(); for (size_t majorAxisIndex = 0; majorAxisIndex < endOfMajorAxis; ++majorAxisIndex) { GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), majorAxisIndex); - if (OwnPtr<GridCoordinate> emptyGridArea = iterator.nextEmptyGridArea()) { - insertItemIntoGrid(gridItem, emptyGridArea->rows.initialPositionIndex, emptyGridArea->columns.initialPositionIndex); - return; + emptyGridArea = iterator.nextEmptyGridArea(majorAxisPositions.integerSpan(), minorAxisPositions.integerSpan()); + + if (emptyGridArea) { + // Check that it fits in the minor axis direction, as we shouldn't grow in that direction here (it was already managed in populateExplicitGridAndOrderIterator()). + GridResolvedPosition minorAxisFinalPositionIndex = autoPlacementMinorAxisDirection() == ForColumns ? emptyGridArea->columns.resolvedFinalPosition : emptyGridArea->rows.resolvedFinalPosition; + const size_t endOfMinorAxis = autoPlacementMinorAxisDirection() == ForColumns ? gridColumnCount() : gridRowCount(); + if (minorAxisFinalPositionIndex.toInt() < endOfMinorAxis) + break; + + // Discard empty grid area as it does not fit in the minor axis direction. + // We don't need to create a new empty grid area yet as we might find a valid one in the next iteration. + emptyGridArea = nullptr; } } + + if (!emptyGridArea) + emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(gridItem, autoPlacementMinorAxisDirection(), minorAxisPositions); } - // We didn't find an empty grid area so we need to create an extra major axis line and insert our gridItem in it. - const size_t columnIndex = (autoPlacementMajorAxisDirection() == ForColumns) ? m_grid[0].size() : minorAxisIndex; - const size_t rowIndex = (autoPlacementMajorAxisDirection() == ForColumns) ? minorAxisIndex : m_grid.size(); - growGrid(autoPlacementMajorAxisDirection()); - insertItemIntoGrid(gridItem, rowIndex, columnIndex); + insertItemIntoGrid(gridItem, *emptyGridArea); } GridTrackSizingDirection RenderGrid::autoPlacementMajorAxisDirection() const @@ -832,6 +953,8 @@ void RenderGrid::dirtyGrid() m_grid.resize(0); m_gridItemCoordinate.clear(); m_gridIsDirty = true; + m_gridItemsOverflowingGridArea.resize(0); + m_gridItemsIndexesMap.clear(); } void RenderGrid::layoutGridItems() @@ -839,12 +962,13 @@ void RenderGrid::layoutGridItems() placeItemsOnGrid(); GridSizingData sizingData(gridColumnCount(), gridRowCount()); - computedUsedBreadthOfGridTracks(ForColumns, sizingData); + computeUsedBreadthOfGridTracks(ForColumns, sizingData); ASSERT(tracksAreWiderThanMinTrackBreadth(ForColumns, sizingData.columnTracks)); - computedUsedBreadthOfGridTracks(ForRows, sizingData); + computeUsedBreadthOfGridTracks(ForRows, sizingData); ASSERT(tracksAreWiderThanMinTrackBreadth(ForRows, sizingData.rowTracks)); populateGridPositions(sizingData); + m_gridItemsOverflowingGridArea.resize(0); for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { // Because the grid area cannot be styled, we don't need to adjust @@ -855,7 +979,7 @@ void RenderGrid::layoutGridItems() LayoutUnit overrideContainingBlockContentLogicalWidth = gridAreaBreadthForChild(child, ForColumns, sizingData.columnTracks); LayoutUnit overrideContainingBlockContentLogicalHeight = gridAreaBreadthForChild(child, ForRows, sizingData.rowTracks); - SubtreeLayoutScope layoutScope(child); + SubtreeLayoutScope layoutScope(*child); if (oldOverrideContainingBlockContentLogicalWidth != overrideContainingBlockContentLogicalWidth || (oldOverrideContainingBlockContentLogicalHeight != overrideContainingBlockContentLogicalHeight && child->hasRelativeLogicalHeight())) layoutScope.setNeedsLayout(child); @@ -869,16 +993,23 @@ void RenderGrid::layoutGridItems() // now, just size as if we were a regular child. child->layoutIfNeeded(); - child->setLogicalLocation(findChildLogicalPosition(child, sizingData)); +#ifndef NDEBUG + const GridCoordinate& coordinate = cachedGridCoordinate(child); + ASSERT(coordinate.columns.resolvedInitialPosition.toInt() < sizingData.columnTracks.size()); + ASSERT(coordinate.rows.resolvedInitialPosition.toInt() < sizingData.rowTracks.size()); +#endif + child->setLogicalLocation(findChildLogicalPosition(child)); - // For correctness, we disable some painting optimizations if we have a child overflowing its grid area. - m_gridItemOverflowGridArea = child->logicalHeight() > overrideContainingBlockContentLogicalHeight - || child->logicalWidth() > overrideContainingBlockContentLogicalWidth; + // Keep track of children overflowing their grid area as we might need to paint them even if the grid-area is + // not visible + if (child->logicalHeight() > overrideContainingBlockContentLogicalHeight + || child->logicalWidth() > overrideContainingBlockContentLogicalWidth) + m_gridItemsOverflowingGridArea.append(child); // If the child moved, we have to repaint it as well as any floating/positioned // descendants. An exception is if we need a layout. In this case, we know we're going to // repaint ourselves (and the child) anyway. - if (!selfNeedsLayout() && child->checkForRepaintDuringLayout()) + if (!selfNeedsLayout() && child->checkForPaintInvalidationDuringLayout()) child->repaintDuringLayoutIfMoved(oldChildRect); } @@ -896,243 +1027,219 @@ GridCoordinate RenderGrid::cachedGridCoordinate(const RenderBox* gridItem) const return m_gridItemCoordinate.get(gridItem); } -GridSpan RenderGrid::resolveGridPositionsFromAutoPlacementPosition(const RenderBox*, GridTrackSizingDirection, size_t initialPosition) const +LayoutUnit RenderGrid::gridAreaBreadthForChild(const RenderBox* child, GridTrackSizingDirection direction, const Vector<GridTrack>& tracks) const { - // FIXME: We don't support spanning with auto positions yet. Once we do, this is wrong. Also we should make - // sure the grid can accomodate the new item as we only grow 1 position in a given direction. - return GridSpan(initialPosition, initialPosition); + const GridCoordinate& coordinate = cachedGridCoordinate(child); + const GridSpan& span = (direction == ForColumns) ? coordinate.columns : coordinate.rows; + LayoutUnit gridAreaBreadth = 0; + for (GridSpan::iterator trackPosition = span.begin(); trackPosition != span.end(); ++trackPosition) + gridAreaBreadth += tracks[trackPosition.toInt()].m_usedBreadth; + return gridAreaBreadth; } -PassOwnPtr<GridSpan> RenderGrid::resolveGridPositionsFromStyle(const RenderBox* gridItem, GridTrackSizingDirection direction) const +void RenderGrid::populateGridPositions(const GridSizingData& sizingData) { - const GridPosition& initialPosition = (direction == ForColumns) ? gridItem->style()->gridColumnStart() : gridItem->style()->gridRowStart(); - const GridPositionSide initialPositionSide = (direction == ForColumns) ? ColumnStartSide : RowStartSide; - const GridPosition& finalPosition = (direction == ForColumns) ? gridItem->style()->gridColumnEnd() : gridItem->style()->gridRowEnd(); - const GridPositionSide finalPositionSide = (direction == ForColumns) ? ColumnEndSide : RowEndSide; - - // We should NEVER see both spans as they should have been handled during style resolve. - ASSERT(!initialPosition.isSpan() || !finalPosition.isSpan()); - - if (initialPosition.shouldBeResolvedAgainstOppositePosition() && finalPosition.shouldBeResolvedAgainstOppositePosition()) { - if (style()->gridAutoFlow() == AutoFlowNone) - return adoptPtr(new GridSpan(0, 0)); - - // We can't get our grid positions without running the auto placement algorithm. - return nullptr; - } - - if (initialPosition.shouldBeResolvedAgainstOppositePosition()) { - // Infer the position from the final position ('auto / 1' or 'span 2 / 3' case). - const size_t finalResolvedPosition = resolveGridPositionFromStyle(finalPosition, finalPositionSide); - return resolveGridPositionAgainstOppositePosition(finalResolvedPosition, initialPosition, initialPositionSide); - } - - if (finalPosition.shouldBeResolvedAgainstOppositePosition()) { - // Infer our position from the initial position ('1 / auto' or '3 / span 2' case). - const size_t initialResolvedPosition = resolveGridPositionFromStyle(initialPosition, initialPositionSide); - return resolveGridPositionAgainstOppositePosition(initialResolvedPosition, finalPosition, finalPositionSide); - } - - size_t resolvedInitialPosition = resolveGridPositionFromStyle(initialPosition, initialPositionSide); - size_t resolvedFinalPosition = resolveGridPositionFromStyle(finalPosition, finalPositionSide); - - // If 'grid-after' specifies a line at or before that specified by 'grid-before', it computes to 'span 1'. - if (resolvedFinalPosition < resolvedInitialPosition) - resolvedFinalPosition = resolvedInitialPosition; + m_columnPositions.resize(sizingData.columnTracks.size() + 1); + m_columnPositions[0] = borderAndPaddingStart(); + for (size_t i = 0; i < m_columnPositions.size() - 1; ++i) + m_columnPositions[i + 1] = m_columnPositions[i] + sizingData.columnTracks[i].m_usedBreadth; - return adoptPtr(new GridSpan(resolvedInitialPosition, resolvedFinalPosition)); + m_rowPositions.resize(sizingData.rowTracks.size() + 1); + m_rowPositions[0] = borderAndPaddingBefore(); + for (size_t i = 0; i < m_rowPositions.size() - 1; ++i) + m_rowPositions[i + 1] = m_rowPositions[i] + sizingData.rowTracks[i].m_usedBreadth; } -size_t RenderGrid::resolveNamedGridLinePositionFromStyle(const GridPosition& position, GridPositionSide side) const +LayoutUnit RenderGrid::startOfColumnForChild(const RenderBox* child) const { - ASSERT(!position.namedGridLine().isNull()); - - const NamedGridLinesMap& gridLinesNames = (side == ColumnStartSide || side == ColumnEndSide) ? style()->namedGridColumnLines() : style()->namedGridRowLines(); - NamedGridLinesMap::const_iterator it = gridLinesNames.find(position.namedGridLine()); - if (it == gridLinesNames.end()) { - if (position.isPositive()) - return 0; - const size_t lastLine = explicitGridSizeForSide(side); - return GridPosition::adjustGridPositionForSide(lastLine, side); - } - - size_t namedGridLineIndex; - if (position.isPositive()) - namedGridLineIndex = std::min<size_t>(position.integerPosition(), it->value.size()) - 1; - else - namedGridLineIndex = std::max<int>(it->value.size() - abs(position.integerPosition()), 0); - return GridPosition::adjustGridPositionForSide(it->value[namedGridLineIndex], side); + const GridCoordinate& coordinate = cachedGridCoordinate(child); + LayoutUnit startOfColumn = m_columnPositions[coordinate.columns.resolvedInitialPosition.toInt()]; + // The grid items should be inside the grid container's border box, that's why they need to be shifted. + // FIXME: This should account for the grid item's <overflow-position>. + return startOfColumn + marginStartForChild(child); } -size_t RenderGrid::resolveGridPositionFromStyle(const GridPosition& position, GridPositionSide side) const +LayoutUnit RenderGrid::endOfColumnForChild(const RenderBox* child) const { - switch (position.type()) { - case ExplicitPosition: { - ASSERT(position.integerPosition()); - - if (!position.namedGridLine().isNull()) - return resolveNamedGridLinePositionFromStyle(position, side); - - // Handle <integer> explicit position. - if (position.isPositive()) - return GridPosition::adjustGridPositionForSide(position.integerPosition() - 1, side); - - size_t resolvedPosition = abs(position.integerPosition()) - 1; - const size_t endOfTrack = explicitGridSizeForSide(side); - - // Per http://lists.w3.org/Archives/Public/www-style/2013Mar/0589.html, we clamp negative value to the first line. - if (endOfTrack < resolvedPosition) - return 0; + const GridCoordinate& coordinate = cachedGridCoordinate(child); + LayoutUnit startOfColumn = m_columnPositions[coordinate.columns.resolvedInitialPosition.toInt()]; + // The grid items should be inside the grid container's border box, that's why they need to be shifted. + LayoutUnit columnPosition = startOfColumn + marginStartForChild(child); - return GridPosition::adjustGridPositionForSide(endOfTrack - resolvedPosition, side); - } - case NamedGridAreaPosition: - { - NamedGridAreaMap::const_iterator it = style()->namedGridArea().find(position.namedGridLine()); - // Unknown grid area should have been computed to 'auto' by now. - ASSERT_WITH_SECURITY_IMPLICATION(it != style()->namedGridArea().end()); - const GridCoordinate& gridAreaCoordinate = it->value; - switch (side) { - case ColumnStartSide: - return gridAreaCoordinate.columns.initialPositionIndex; - case ColumnEndSide: - return gridAreaCoordinate.columns.finalPositionIndex; - case RowStartSide: - return gridAreaCoordinate.rows.initialPositionIndex; - case RowEndSide: - return gridAreaCoordinate.rows.finalPositionIndex; - } - ASSERT_NOT_REACHED(); - return 0; - } - case AutoPosition: - case SpanPosition: - // 'auto' and span depend on the opposite position for resolution (e.g. grid-row: auto / 1 or grid-column: span 3 / "myHeader"). - ASSERT_NOT_REACHED(); - return 0; - } - ASSERT_NOT_REACHED(); - return 0; + LayoutUnit endOfColumn = m_columnPositions[coordinate.columns.resolvedFinalPosition.next().toInt()]; + // FIXME: This should account for the grid item's <overflow-position>. + return columnPosition + std::max<LayoutUnit>(0, endOfColumn - m_columnPositions[coordinate.columns.resolvedInitialPosition.toInt()] - child->logicalWidth()); } -PassOwnPtr<GridSpan> RenderGrid::resolveGridPositionAgainstOppositePosition(size_t resolvedOppositePosition, const GridPosition& position, GridPositionSide side) const +LayoutUnit RenderGrid::columnPositionAlignedWithGridContainerStart(const RenderBox* child) const { - if (position.isAuto()) - return GridSpan::create(resolvedOppositePosition, resolvedOppositePosition); + if (style()->isLeftToRightDirection()) + return startOfColumnForChild(child); - ASSERT(position.isSpan()); - ASSERT(position.spanPosition() > 0); - - if (!position.namedGridLine().isNull()) { - // span 2 'c' -> we need to find the appropriate grid line before / after our opposite position. - return resolveNamedGridLinePositionAgainstOppositePosition(resolvedOppositePosition, position, side); - } - - return GridSpan::createWithSpanAgainstOpposite(resolvedOppositePosition, position, side); + return endOfColumnForChild(child); } -PassOwnPtr<GridSpan> RenderGrid::resolveNamedGridLinePositionAgainstOppositePosition(size_t resolvedOppositePosition, const GridPosition& position, GridPositionSide side) const +LayoutUnit RenderGrid::columnPositionAlignedWithGridContainerEnd(const RenderBox* child) const { - ASSERT(position.isSpan()); - ASSERT(!position.namedGridLine().isNull()); - // Negative positions are not allowed per the specification and should have been handled during parsing. - ASSERT(position.spanPosition() > 0); + if (!style()->isLeftToRightDirection()) + return startOfColumnForChild(child); - const NamedGridLinesMap& gridLinesNames = (side == ColumnStartSide || side == ColumnEndSide) ? style()->namedGridColumnLines() : style()->namedGridRowLines(); - NamedGridLinesMap::const_iterator it = gridLinesNames.find(position.namedGridLine()); - - // If there is no named grid line of that name, we resolve the position to 'auto' (which is equivalent to 'span 1' in this case). - // See http://lists.w3.org/Archives/Public/www-style/2013Jun/0394.html. - if (it == gridLinesNames.end()) - return GridSpan::create(resolvedOppositePosition, resolvedOppositePosition); - - return GridSpan::createWithNamedSpanAgainstOpposite(resolvedOppositePosition, position, side, it->value); + return endOfColumnForChild(child); } -LayoutUnit RenderGrid::gridAreaBreadthForChild(const RenderBox* child, GridTrackSizingDirection direction, const Vector<GridTrack>& tracks) const +LayoutUnit RenderGrid::centeredColumnPositionForChild(const RenderBox* child) const { const GridCoordinate& coordinate = cachedGridCoordinate(child); - const GridSpan& span = (direction == ForColumns) ? coordinate.columns : coordinate.rows; - LayoutUnit gridAreaBreadth = 0; - for (size_t trackIndex = span.initialPositionIndex; trackIndex <= span.finalPositionIndex; ++trackIndex) - gridAreaBreadth += tracks[trackIndex].m_usedBreadth; - return gridAreaBreadth; + LayoutUnit startOfColumn = m_columnPositions[coordinate.columns.resolvedInitialPosition.toInt()]; + LayoutUnit endOfColumn = m_columnPositions[coordinate.columns.resolvedFinalPosition.next().toInt()]; + LayoutUnit columnPosition = startOfColumn + marginStartForChild(child); + return columnPosition + std::max<LayoutUnit>(0, endOfColumn - startOfColumn - child->logicalWidth()) / 2; } -void RenderGrid::populateGridPositions(const GridSizingData& sizingData) +LayoutUnit RenderGrid::columnPositionForChild(const RenderBox* child) const { - m_columnPositions.resize(sizingData.columnTracks.size() + 1); - m_columnPositions[0] = borderAndPaddingStart(); - for (size_t i = 0; i < m_columnPositions.size() - 1; ++i) - m_columnPositions[i + 1] = m_columnPositions[i] + sizingData.columnTracks[i].m_usedBreadth; + ItemPosition childJustifySelf = child->style()->justifySelf(); + switch (childJustifySelf) { + case ItemPositionSelfStart: + // self-start is based on the child's direction. That's why we need to check against the grid container's direction. + if (child->style()->direction() != style()->direction()) + return columnPositionAlignedWithGridContainerEnd(child); + + return columnPositionAlignedWithGridContainerStart(child); + case ItemPositionSelfEnd: + // self-end is based on the child's direction. That's why we need to check against the grid container's direction. + if (child->style()->direction() != style()->direction()) + return columnPositionAlignedWithGridContainerStart(child); + + return columnPositionAlignedWithGridContainerEnd(child); + + case ItemPositionFlexStart: + case ItemPositionFlexEnd: + // Only used in flex layout, for other layout, it's equivalent to 'start'. + return columnPositionAlignedWithGridContainerStart(child); + + case ItemPositionLeft: + // If the property's axis is not parallel with the inline axis, this is equivalent to ‘start’. + if (!isHorizontalWritingMode()) + return columnPositionAlignedWithGridContainerStart(child); + + if (style()->isLeftToRightDirection()) + return columnPositionAlignedWithGridContainerStart(child); + + return columnPositionAlignedWithGridContainerEnd(child); + case ItemPositionRight: + // If the property's axis is not parallel with the inline axis, this is equivalent to ‘start’. + if (!isHorizontalWritingMode()) + return columnPositionAlignedWithGridContainerStart(child); + + if (style()->isLeftToRightDirection()) + return columnPositionAlignedWithGridContainerEnd(child); + + return columnPositionAlignedWithGridContainerStart(child); + + case ItemPositionCenter: + return centeredColumnPositionForChild(child); + case ItemPositionStart: + return columnPositionAlignedWithGridContainerStart(child); + case ItemPositionEnd: + return columnPositionAlignedWithGridContainerEnd(child); + + case ItemPositionAuto: + case ItemPositionStretch: + case ItemPositionBaseline: + // FIXME: Implement the previous values. For now, we always start align the child. + return startOfColumnForChild(child); + } - m_rowPositions.resize(sizingData.rowTracks.size() + 1); - m_rowPositions[0] = borderAndPaddingBefore(); - for (size_t i = 0; i < m_rowPositions.size() - 1; ++i) - m_rowPositions[i + 1] = m_rowPositions[i] + sizingData.rowTracks[i].m_usedBreadth; + ASSERT_NOT_REACHED(); + return 0; } -LayoutPoint RenderGrid::findChildLogicalPosition(RenderBox* child, const GridSizingData& sizingData) +LayoutUnit RenderGrid::rowPositionForChild(const RenderBox* child) const { const GridCoordinate& coordinate = cachedGridCoordinate(child); - ASSERT(coordinate.columns.initialPositionIndex < sizingData.columnTracks.size()); - ASSERT(coordinate.rows.initialPositionIndex < sizingData.rowTracks.size()); // The grid items should be inside the grid container's border box, that's why they need to be shifted. - return LayoutPoint(m_columnPositions[coordinate.columns.initialPositionIndex] + marginStartForChild(child), m_rowPositions[coordinate.rows.initialPositionIndex] + marginBeforeForChild(child)); + LayoutUnit startOfRow = m_rowPositions[coordinate.rows.resolvedInitialPosition.toInt()]; + LayoutUnit rowPosition = startOfRow + marginBeforeForChild(child); + + // FIXME: This function should account for 'align-self'. + + return rowPosition; +} + +LayoutPoint RenderGrid::findChildLogicalPosition(const RenderBox* child) const +{ + return LayoutPoint(columnPositionForChild(child), rowPositionForChild(child)); } static GridSpan dirtiedGridAreas(const Vector<LayoutUnit>& coordinates, LayoutUnit start, LayoutUnit end) { // This function does a binary search over the coordinates. - // FIXME: This doesn't work with grid items overflowing their grid areas and should be tested & fixed. + // This doesn't work with grid items overflowing their grid areas, but that is managed with m_gridItemsOverflowingGridArea. size_t startGridAreaIndex = std::upper_bound(coordinates.begin(), coordinates.end() - 1, start) - coordinates.begin(); if (startGridAreaIndex > 0) --startGridAreaIndex; size_t endGridAreaIndex = std::upper_bound(coordinates.begin() + startGridAreaIndex, coordinates.end() - 1, end) - coordinates.begin(); + if (endGridAreaIndex > 0) + --endGridAreaIndex; + return GridSpan(startGridAreaIndex, endGridAreaIndex); } -void RenderGrid::paintChildrenSlowCase(PaintInfo& paintInfo, const LayoutPoint& paintOffset) -{ - for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) - paintChild(child, paintInfo, paintOffset); -} +class GridItemsSorter { +public: + bool operator()(const std::pair<RenderBox*, size_t> firstChild, const std::pair<RenderBox*, size_t> secondChild) const + { + if (firstChild.first->style()->order() != secondChild.first->style()->order()) + return firstChild.first->style()->order() < secondChild.first->style()->order(); + + return firstChild.second < secondChild.second; + } +}; void RenderGrid::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { ASSERT_WITH_SECURITY_IMPLICATION(!gridIsDirty()); - if (m_gridItemOverflowGridArea) { - paintChildrenSlowCase(paintInfo, paintOffset); - return; - } - LayoutRect localRepaintRect = paintInfo.rect; localRepaintRect.moveBy(-paintOffset); GridSpan dirtiedColumns = dirtiedGridAreas(m_columnPositions, localRepaintRect.x(), localRepaintRect.maxX()); GridSpan dirtiedRows = dirtiedGridAreas(m_rowPositions, localRepaintRect.y(), localRepaintRect.maxY()); - OrderIterator paintIterator(this); - { - OrderIteratorPopulator populator(paintIterator); - - for (size_t row = dirtiedRows.initialPositionIndex; row < dirtiedRows.finalPositionIndex; ++row) { - for (size_t column = dirtiedColumns.initialPositionIndex; column < dirtiedColumns.finalPositionIndex; ++column) { - const Vector<RenderBox*, 1>& children = m_grid[row][column]; - // FIXME: If we start adding spanning children in all grid areas they span, this - // would make us paint them several times, which is wrong! - for (size_t j = 0; j < children.size(); ++j) - populator.storeChild(children[j]); - } + Vector<std::pair<RenderBox*, size_t> > gridItemsToBePainted; + + for (GridSpan::iterator row = dirtiedRows.begin(); row != dirtiedRows.end(); ++row) { + for (GridSpan::iterator column = dirtiedColumns.begin(); column != dirtiedColumns.end(); ++column) { + const Vector<RenderBox*, 1>& children = m_grid[row.toInt()][column.toInt()]; + for (size_t j = 0; j < children.size(); ++j) + gridItemsToBePainted.append(std::make_pair(children[j], m_gridItemsIndexesMap.get(children[j]))); } } - for (RenderBox* child = paintIterator.first(); child; child = paintIterator.next()) - paintChild(child, paintInfo, paintOffset); + for (Vector<RenderBox*>::const_iterator it = m_gridItemsOverflowingGridArea.begin(); it != m_gridItemsOverflowingGridArea.end(); ++it) { + if ((*it)->frameRect().intersects(localRepaintRect)) + gridItemsToBePainted.append(std::make_pair(*it, m_gridItemsIndexesMap.get(*it))); + } + + // Sort grid items following order-modified document order. + // See http://www.w3.org/TR/css-flexbox/#order-modified-document-order + std::stable_sort(gridItemsToBePainted.begin(), gridItemsToBePainted.end(), GridItemsSorter()); + + RenderBox* previous = 0; + for (Vector<std::pair<RenderBox*, size_t> >::const_iterator it = gridItemsToBePainted.begin(); it != gridItemsToBePainted.end(); ++it) { + // We might have duplicates because of spanning children are included in all cells they span. + // Skip them here to avoid painting items several times. + RenderBox* current = (*it).first; + if (current == previous) + continue; + + paintChild(current, paintInfo, paintOffset); + previous = current; + } } const char* RenderGrid::renderName() const diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderGrid.h b/chromium/third_party/WebKit/Source/core/rendering/RenderGrid.h index f8a4de326f5..d06e2632141 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderGrid.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderGrid.h @@ -28,6 +28,7 @@ #include "core/rendering/OrderIterator.h" #include "core/rendering/RenderBlock.h" +#include "core/rendering/style/GridResolvedPosition.h" namespace WebCore { @@ -35,11 +36,6 @@ struct GridCoordinate; struct GridSpan; class GridTrack; -enum GridTrackSizingDirection { - ForColumns, - ForRows -}; - class RenderGrid FINAL : public RenderBlock { public: RenderGrid(Element*); @@ -47,7 +43,7 @@ public: virtual const char* renderName() const OVERRIDE; - virtual void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0) OVERRIDE; + virtual void layoutBlock(bool relayoutChildren) OVERRIDE; virtual bool avoidsFloats() const OVERRIDE { return true; } virtual bool canCollapseAnonymousBlockChild() const OVERRIDE { return false; } @@ -63,6 +59,7 @@ private: virtual void computePreferredLogicalWidths() OVERRIDE; virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0) OVERRIDE; + void addChildToIndexesMap(RenderBox*); virtual void removeChild(RenderObject*) OVERRIDE; virtual void styleDidChange(StyleDifference, const RenderStyle*) OVERRIDE; @@ -72,18 +69,19 @@ private: class GridIterator; struct GridSizingData; - void computedUsedBreadthOfGridTracks(GridTrackSizingDirection, GridSizingData&); - void computedUsedBreadthOfGridTracks(GridTrackSizingDirection, GridSizingData&, LayoutUnit& availableLogicalSpace); + bool gridElementIsShrinkToFit(); + void computeUsedBreadthOfGridTracks(GridTrackSizingDirection, GridSizingData&); + void computeUsedBreadthOfGridTracks(GridTrackSizingDirection, GridSizingData&, LayoutUnit& availableLogicalSpace); LayoutUnit computeUsedBreadthOfMinLength(GridTrackSizingDirection, const GridLength&) const; LayoutUnit computeUsedBreadthOfMaxLength(GridTrackSizingDirection, const GridLength&, LayoutUnit usedBreadth) const; LayoutUnit computeUsedBreadthOfSpecifiedLength(GridTrackSizingDirection, const Length&) const; void resolveContentBasedTrackSizingFunctions(GridTrackSizingDirection, GridSizingData&, LayoutUnit& availableLogicalSpace); - void growGrid(GridTrackSizingDirection); - void insertItemIntoGrid(RenderBox*, size_t rowTrack, size_t columnTrack); + void ensureGridSize(size_t maximumRowIndex, size_t maximumColumnIndex); void insertItemIntoGrid(RenderBox*, const GridCoordinate&); void placeItemsOnGrid(); void populateExplicitGridAndOrderIterator(); + PassOwnPtr<GridCoordinate> createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(const RenderBox*, GridTrackSizingDirection, const GridSpan& specifiedPositions) const; void placeSpecifiedMajorAxisItemsOnGrid(const Vector<RenderBox*>&); void placeAutoMajorAxisItemsOnGrid(const Vector<RenderBox*>&); void placeAutoMajorAxisItemOnGrid(RenderBox*); @@ -93,8 +91,6 @@ private: void layoutGridItems(); void populateGridPositions(const GridSizingData&); - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - typedef LayoutUnit (RenderGrid::* SizingFunction)(RenderBox*, GridTrackSizingDirection, Vector<GridTrack>&); typedef LayoutUnit (GridTrack::* AccumulatorGetter)() const; typedef void (GridTrack::* AccumulatorGrowFunction)(LayoutUnit); @@ -102,32 +98,26 @@ private: void resolveContentBasedTrackSizingFunctionsForItems(GridTrackSizingDirection, GridSizingData&, RenderBox*, FilterFunction, SizingFunction, AccumulatorGetter, AccumulatorGrowFunction); void distributeSpaceToTracks(Vector<GridTrack*>&, Vector<GridTrack*>* tracksForGrowthAboveMaxBreadth, AccumulatorGetter, AccumulatorGrowFunction, GridSizingData&, LayoutUnit& availableLogicalSpace); - double computeNormalizedFractionBreadth(Vector<GridTrack>&, GridTrackSizingDirection, LayoutUnit availableLogicalSpace) const; + double computeNormalizedFractionBreadth(Vector<GridTrack>&, const GridSpan& tracksSpan, GridTrackSizingDirection, LayoutUnit availableLogicalSpace) const; const GridTrackSize& gridTrackSize(GridTrackSizingDirection, size_t) const; - size_t explicitGridColumnCount() const; - size_t explicitGridRowCount() const; - size_t explicitGridSizeForSide(GridPositionSide) const; - LayoutUnit logicalContentHeightForChild(RenderBox*, Vector<GridTrack>&); + LayoutUnit logicalHeightForChild(RenderBox*, Vector<GridTrack>&); LayoutUnit minContentForChild(RenderBox*, GridTrackSizingDirection, Vector<GridTrack>& columnTracks); LayoutUnit maxContentForChild(RenderBox*, GridTrackSizingDirection, Vector<GridTrack>& columnTracks); - LayoutPoint findChildLogicalPosition(RenderBox*, const GridSizingData&); + LayoutUnit startOfColumnForChild(const RenderBox* child) const; + LayoutUnit endOfColumnForChild(const RenderBox* child) const; + LayoutUnit columnPositionAlignedWithGridContainerStart(const RenderBox*) const; + LayoutUnit columnPositionAlignedWithGridContainerEnd(const RenderBox*) const; + LayoutUnit centeredColumnPositionForChild(const RenderBox*) const; + LayoutUnit columnPositionForChild(const RenderBox*) const; + LayoutUnit rowPositionForChild(const RenderBox*) const; + LayoutPoint findChildLogicalPosition(const RenderBox*) const; GridCoordinate cachedGridCoordinate(const RenderBox*) const; - GridSpan resolveGridPositionsFromAutoPlacementPosition(const RenderBox*, GridTrackSizingDirection, size_t) const; - PassOwnPtr<GridSpan> resolveGridPositionsFromStyle(const RenderBox*, GridTrackSizingDirection) const; - size_t resolveNamedGridLinePositionFromStyle(const GridPosition&, GridPositionSide) const; - size_t resolveGridPositionFromStyle(const GridPosition&, GridPositionSide) const; - PassOwnPtr<GridSpan> resolveGridPositionAgainstOppositePosition(size_t resolvedOppositePosition, const GridPosition&, GridPositionSide) const; - PassOwnPtr<GridSpan> resolveNamedGridLinePositionAgainstOppositePosition(size_t resolvedOppositePosition, const GridPosition&, GridPositionSide) const; - PassOwnPtr<GridSpan> resolveBeforeStartNamedGridLinePositionAgainstOppositePosition(size_t resolvedOppositePosition, const GridPosition&, const Vector<size_t>&) const; - PassOwnPtr<GridSpan> resolveAfterEndNamedGridLinePositionAgainstOppositePosition(size_t resolvedOppositePosition, const GridPosition&, const Vector<size_t>&) const; - LayoutUnit gridAreaBreadthForChild(const RenderBox* child, GridTrackSizingDirection, const Vector<GridTrack>&) const; - virtual void paintChildren(PaintInfo&, const LayoutPoint&) OVERRIDE FINAL; - void paintChildrenSlowCase(PaintInfo&, const LayoutPoint&); + virtual void paintChildren(PaintInfo&, const LayoutPoint&) OVERRIDE; bool gridIsDirty() const { return m_gridIsDirty; } @@ -154,7 +144,8 @@ private: Vector<LayoutUnit> m_columnPositions; HashMap<const RenderBox*, GridCoordinate> m_gridItemCoordinate; OrderIterator m_orderIterator; - bool m_gridItemOverflowGridArea; + Vector<RenderBox*> m_gridItemsOverflowingGridArea; + HashMap<const RenderBox*, size_t> m_gridItemsIndexesMap; }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderGrid, isRenderGrid()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderHTMLCanvas.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderHTMLCanvas.cpp index 96a06bbb5fd..41a29420906 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderHTMLCanvas.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderHTMLCanvas.cpp @@ -28,8 +28,8 @@ #include "core/html/HTMLCanvasElement.h" #include "core/html/canvas/CanvasRenderingContext.h" -#include "core/frame/Frame.h" #include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/page/Page.h" #include "core/rendering/PaintInfo.h" #include "core/rendering/RenderView.h" @@ -44,13 +44,9 @@ RenderHTMLCanvas::RenderHTMLCanvas(HTMLCanvasElement* element) view()->frameView()->setIsVisuallyNonEmpty(); } -bool RenderHTMLCanvas::requiresLayer() const +LayerType RenderHTMLCanvas::layerTypeRequired() const { - if (RenderReplaced::requiresLayer()) - return true; - - HTMLCanvasElement* canvas = toHTMLCanvasElement(node()); - return canvas && canvas->renderingContext() && canvas->renderingContext()->isAccelerated(); + return NormalLayer; } void RenderHTMLCanvas::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) @@ -69,8 +65,13 @@ void RenderHTMLCanvas::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& pa paintInfo.context->clip(pixelSnappedIntRect(contentRect)); } - bool useLowQualityScale = style()->imageRendering() == ImageRenderingOptimizeContrast; - toHTMLCanvasElement(node())->paint(context, paintRect, useLowQualityScale); + // FIXME: InterpolationNone should be used if ImageRenderingOptimizeContrast is set. + // See bug for more details: crbug.com/353716. + InterpolationQuality interpolationQuality = style()->imageRendering() == ImageRenderingOptimizeContrast ? InterpolationLow : CanvasDefaultInterpolationQuality; + InterpolationQuality previousInterpolationQuality = context->imageInterpolationQuality(); + context->setImageInterpolationQuality(interpolationQuality); + toHTMLCanvasElement(node())->paint(context, paintRect); + context->setImageInterpolationQuality(previousInterpolationQuality); if (clip) context->restore(); @@ -99,7 +100,19 @@ void RenderHTMLCanvas::canvasSizeChanged() return; if (!selfNeedsLayout()) - setNeedsLayout(); + setNeedsLayoutAndFullPaintInvalidation(); +} + +CompositingReasons RenderHTMLCanvas::additionalCompositingReasons(CompositingTriggerFlags triggers) const +{ + if (!(triggers & CanvasTrigger)) + return CompositingReasonNone; + + HTMLCanvasElement* canvas = toHTMLCanvasElement(node()); + if (canvas->renderingContext() && canvas->renderingContext()->isAccelerated()) + return CompositingReasonCanvas; + + return CompositingReasonNone; } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderHTMLCanvas.h b/chromium/third_party/WebKit/Source/core/rendering/RenderHTMLCanvas.h index 6cdaf64a1da..c06ee44cefc 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderHTMLCanvas.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderHTMLCanvas.h @@ -36,15 +36,17 @@ class RenderHTMLCanvas FINAL : public RenderReplaced { public: explicit RenderHTMLCanvas(HTMLCanvasElement*); - virtual bool isCanvas() const { return true; } - virtual bool requiresLayer() const; + virtual bool isCanvas() const OVERRIDE { return true; } + virtual LayerType layerTypeRequired() const OVERRIDE; void canvasSizeChanged(); private: - virtual const char* renderName() const { return "RenderHTMLCanvas"; } - virtual void paintReplaced(PaintInfo&, const LayoutPoint&); - virtual void intrinsicSizeChanged() { canvasSizeChanged(); } + virtual const char* renderName() const OVERRIDE { return "RenderHTMLCanvas"; } + virtual void paintReplaced(PaintInfo&, const LayoutPoint&) OVERRIDE; + virtual void intrinsicSizeChanged() OVERRIDE { canvasSizeChanged(); } + + virtual CompositingReasons additionalCompositingReasons(CompositingTriggerFlags) const OVERRIDE; }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderHTMLCanvas, isCanvas()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderIFrame.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderIFrame.cpp index 85016ccc523..e783f196778 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderIFrame.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderIFrame.cpp @@ -26,11 +26,10 @@ #include "config.h" #include "core/rendering/RenderIFrame.h" -#include "HTMLNames.h" -#include "core/html/HTMLIFrameElement.h" -#include "core/frame/Frame.h" +#include "core/HTMLNames.h" #include "core/frame/FrameView.h" -#include "core/rendering/LayoutRectRecorder.h" +#include "core/frame/LocalFrame.h" +#include "core/html/HTMLIFrameElement.h" #include "core/rendering/RenderView.h" namespace WebCore { @@ -44,99 +43,32 @@ RenderIFrame::RenderIFrame(Element* element) bool RenderIFrame::shouldComputeSizeAsReplaced() const { - // When we're seamless, we use normal block/box sizing code except when inline. - return !isSeamless(); + return true; } bool RenderIFrame::isInlineBlockOrInlineTable() const { - return isSeamless() && isInline(); -} - -LayoutUnit RenderIFrame::minPreferredLogicalWidth() const -{ - if (!isSeamless()) - return RenderPart::minPreferredLogicalWidth(); - - RenderView* childRoot = contentRootRenderer(); - if (!childRoot) - return 0; - - return childRoot->minPreferredLogicalWidth() + borderAndPaddingLogicalWidth(); -} - -LayoutUnit RenderIFrame::maxPreferredLogicalWidth() const -{ - if (!isSeamless()) - return RenderPart::maxPreferredLogicalWidth(); - - RenderView* childRoot = contentRootRenderer(); - if (!childRoot) - return 0; - - return childRoot->maxPreferredLogicalWidth() + borderAndPaddingLogicalWidth(); -} - -bool RenderIFrame::isSeamless() const -{ - return node() && node()->hasTagName(iframeTag) && toHTMLIFrameElement(node())->shouldDisplaySeamlessly(); -} - -bool RenderIFrame::requiresLayer() const -{ - return RenderPart::requiresLayer() || style()->resize() != RESIZE_NONE; -} - -RenderView* RenderIFrame::contentRootRenderer() const -{ - // FIXME: Is this always a valid cast? What about plugins? - ASSERT(!widget() || widget()->isFrameView()); - FrameView* childFrameView = toFrameView(widget()); - return childFrameView ? childFrameView->frame().contentRenderer() : 0; + return isInline(); } -void RenderIFrame::layoutSeamlessly() +LayerType RenderIFrame::layerTypeRequired() const { - updateLogicalWidth(); - // FIXME: Containers set their height to 0 before laying out their kids (as we're doing here) - // however, this causes FrameView::layout() to add vertical scrollbars, incorrectly inflating - // the resulting contentHeight(). We'll need to make FrameView::layout() smarter. - setLogicalHeight(0); - updateWidgetPosition(); // Tell the Widget about our new width/height (it will also layout the child document). - - // Laying out our kids is normally responsible for adjusting our height, so we set it here. - // Replaced elements normally do not respect padding, but seamless elements should: we'll add - // both padding and border to the child's logical height here. - FrameView* childFrameView = toFrameView(widget()); - if (childFrameView) // Widget should never be null during layout(), but just in case. - setLogicalHeight(childFrameView->contentsHeight() + borderTop() + borderBottom() + paddingTop() + paddingBottom()); - updateLogicalHeight(); - - updateWidgetPosition(); // Notify the Widget of our final height. - - // Assert that the child document did a complete layout. - RenderView* childRoot = childFrameView ? childFrameView->frame().contentRenderer() : 0; - ASSERT(!childFrameView || !childFrameView->layoutPending()); - ASSERT_UNUSED(childRoot, !childRoot || !childRoot->needsLayout()); + if (style()->resize() != RESIZE_NONE) + return NormalLayer; + return RenderPart::layerTypeRequired(); } void RenderIFrame::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); - if (isSeamless()) { - layoutSeamlessly(); - // Do not return so as to share the layer and overflow updates below. - } else { - updateLogicalWidth(); - // No kids to layout as a replaced element. - updateLogicalHeight(); - } + updateLogicalWidth(); + // No kids to layout as a replaced element. + updateLogicalHeight(); m_overflow.clear(); addVisualEffectOverflow(); - updateLayerTransform(); + updateLayerTransformAfterLayout(); clearNeedsLayout(); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderIFrame.h b/chromium/third_party/WebKit/Source/core/rendering/RenderIFrame.h index e8a6197c91d..7ec616547c0 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderIFrame.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderIFrame.h @@ -30,18 +30,11 @@ namespace WebCore { -class RenderView; - class RenderIFrame FINAL : public RenderPart { public: explicit RenderIFrame(Element*); - bool isSeamless() const; - private: - virtual LayoutUnit minPreferredLogicalWidth() const OVERRIDE; - virtual LayoutUnit maxPreferredLogicalWidth() const OVERRIDE; - virtual bool shouldComputeSizeAsReplaced() const OVERRIDE; virtual bool isInlineBlockOrInlineTable() const OVERRIDE; @@ -51,11 +44,7 @@ private: virtual const char* renderName() const OVERRIDE { return "RenderPartObject"; } // Lying for now to avoid breaking tests - virtual bool requiresLayer() const OVERRIDE; - - void layoutSeamlessly(); - - RenderView* contentRootRenderer() const; + virtual LayerType layerTypeRequired() const OVERRIDE; }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderIFrame, isRenderIFrame()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderImage.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderImage.cpp index f2db1e3a3a6..610c7906446 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderImage.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderImage.cpp @@ -28,19 +28,19 @@ #include "config.h" #include "core/rendering/RenderImage.h" -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/editing/FrameSelection.h" #include "core/fetch/ImageResource.h" #include "core/fetch/ResourceLoadPriorityOptimizer.h" #include "core/fetch/ResourceLoader.h" +#include "core/frame/LocalFrame.h" #include "core/html/HTMLAreaElement.h" #include "core/html/HTMLImageElement.h" #include "core/html/HTMLInputElement.h" #include "core/html/HTMLMapElement.h" #include "core/inspector/InspectorInstrumentation.h" -#include "core/frame/Frame.h" +#include "core/inspector/InspectorTraceEvents.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/PaintInfo.h" #include "core/rendering/RenderView.h" #include "core/svg/graphics/SVGImage.h" @@ -57,12 +57,12 @@ using namespace HTMLNames; RenderImage::RenderImage(Element* element) : RenderReplaced(element, IntSize()) - , m_needsToSetSizeForAltText(false) , m_didIncrementVisuallyNonEmptyPixelCount(false) , m_isGeneratedContent(false) , m_imageDevicePixelRatio(1.0f) { updateAltText(); + ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->addRenderObject(this); } RenderImage* RenderImage::createAnonymous(Document* document) @@ -141,22 +141,12 @@ bool RenderImage::setImageSizeForAltText(ImageResource* newImage /* = 0 */) return true; } -void RenderImage::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) -{ - RenderReplaced::styleDidChange(diff, oldStyle); - if (m_needsToSetSizeForAltText) { - if (!m_altText.isEmpty() && setImageSizeForAltText(m_imageResource->cachedImage())) - imageDimensionsChanged(true /* imageSizeChanged */); - m_needsToSetSizeForAltText = false; - } -} - void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect) { if (documentBeingDestroyed()) return; - if (hasBoxDecorations() || hasMask()) + if (hasBoxDecorations() || hasMask() || hasShapeOutside()) RenderReplaced::imageChanged(newImage, rect); if (!m_imageResource) @@ -179,29 +169,17 @@ void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect) bool imageSizeChanged = false; // Set image dimensions, taking into account the size of the alt text. - if (m_imageResource->errorOccurred() || !newImage) { - if (!m_altText.isEmpty() && document().hasPendingStyleRecalc()) { - ASSERT(node()); - if (node()) { - m_needsToSetSizeForAltText = true; - node()->setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer); - } - return; - } + if (m_imageResource->errorOccurred() || !newImage) imageSizeChanged = setImageSizeForAltText(m_imageResource->cachedImage()); - } - imageDimensionsChanged(imageSizeChanged, rect); + repaintOrMarkForLayout(imageSizeChanged, rect); } -bool RenderImage::updateIntrinsicSizeIfNeeded(const LayoutSize& newSize, bool imageSizeChanged) +void RenderImage::updateIntrinsicSizeIfNeeded(const LayoutSize& newSize) { - if (newSize == intrinsicSize() && !imageSizeChanged) - return false; if (m_imageResource->errorOccurred() || !m_imageResource->hasImage()) - return imageSizeChanged; + return; setIntrinsicSize(newSize); - return true; } void RenderImage::updateInnerContentRect() @@ -213,9 +191,11 @@ void RenderImage::updateInnerContentRect() m_imageResource->setContainerSizeForRenderer(containerSize); } -void RenderImage::imageDimensionsChanged(bool imageSizeChanged, const IntRect* rect) +void RenderImage::repaintOrMarkForLayout(bool imageSizeChangedToAccomodateAltText, const IntRect* rect) { - bool intrinsicSizeChanged = updateIntrinsicSizeIfNeeded(m_imageResource->intrinsicSize(style()->effectiveZoom()), imageSizeChanged); + LayoutSize oldIntrinsicSize = intrinsicSize(); + LayoutSize newIntrinsicSize = m_imageResource->intrinsicSize(style()->effectiveZoom()); + updateIntrinsicSizeIfNeeded(newIntrinsicSize); // In the case of generated image content using :before/:after/content, we might not be // in the render tree yet. In that case, we just need to update our intrinsic size. @@ -224,37 +204,25 @@ void RenderImage::imageDimensionsChanged(bool imageSizeChanged, const IntRect* r if (!containingBlock()) return; - bool shouldRepaint = true; - if (intrinsicSizeChanged) { - if (!preferredLogicalWidthsDirty()) - setPreferredLogicalWidthsDirty(); + bool imageSourceHasChangedSize = oldIntrinsicSize != newIntrinsicSize || imageSizeChangedToAccomodateAltText; + if (imageSourceHasChangedSize) + setPreferredLogicalWidthsDirty(); - bool hasOverrideSize = hasOverrideHeight() || hasOverrideWidth(); - if (!hasOverrideSize && !imageSizeChanged) { - LogicalExtentComputedValues computedValues; - computeLogicalWidthInRegion(computedValues); - LayoutUnit newWidth = computedValues.m_extent; - computeLogicalHeight(height(), 0, computedValues); - LayoutUnit newHeight = computedValues.m_extent; + // If the actual area occupied by the image has changed and it is not constrained by style then a layout is required. + bool imageSizeIsConstrained = style()->logicalWidth().isSpecified() && style()->logicalHeight().isSpecified(); + bool needsLayout = !imageSizeIsConstrained && imageSourceHasChangedSize; - imageSizeChanged = width() != newWidth || height() != newHeight; - } + // FIXME: We only need to recompute the containing block's preferred size if the containing block's size + // depends on the image's size (i.e., the container uses shrink-to-fit sizing). + // There's no easy way to detect that shrink-to-fit is needed, always force a layout. + bool containingBlockNeedsToRecomputePreferredSize = style()->logicalWidth().isPercent() || style()->logicalMaxWidth().isPercent() || style()->logicalMinWidth().isPercent(); - // FIXME: We only need to recompute the containing block's preferred size - // if the containing block's size depends on the image's size (i.e., the container uses shrink-to-fit sizing). - // There's no easy way to detect that shrink-to-fit is needed, always force a layout. - bool containingBlockNeedsToRecomputePreferredSize = - style()->logicalWidth().isPercent() - || style()->logicalMaxWidth().isPercent() - || style()->logicalMinWidth().isPercent(); - - if (imageSizeChanged || hasOverrideSize || containingBlockNeedsToRecomputePreferredSize) { - shouldRepaint = false; - if (!selfNeedsLayout()) - setNeedsLayout(); - } + if (needsLayout || containingBlockNeedsToRecomputePreferredSize) { + setNeedsLayoutAndFullPaintInvalidation(); + return; } + // The image hasn't changed in size or its style constrains its size, so a repaint will suffice. if (everHadLayout() && !selfNeedsLayout()) { // The inner content rectangle is calculated during layout, but may need an update now // (unless the box has already been scheduled for layout). In order to calculate it, we @@ -263,22 +231,26 @@ void RenderImage::imageDimensionsChanged(bool imageSizeChanged, const IntRect* r updateInnerContentRect(); } - if (shouldRepaint) { - LayoutRect repaintRect; - if (rect) { - // The image changed rect is in source image coordinates (pre-zooming), - // so map from the bounds of the image to the contentsBox. - repaintRect = enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), m_imageResource->imageSize(1.0f)), contentBoxRect())); - // Guard against too-large changed rects. - repaintRect.intersect(contentBoxRect()); - } else - repaintRect = contentBoxRect(); - - repaintRectangle(repaintRect); + LayoutRect repaintRect; + if (rect) { + // The image changed rect is in source image coordinates (without zoom), + // so map from the bounds of the image to the contentsBox. + const LayoutSize imageSizeWithoutZoom = m_imageResource->imageSize(1 / style()->effectiveZoom()); + repaintRect = enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), imageSizeWithoutZoom), contentBoxRect())); + // Guard against too-large changed rects. + repaintRect.intersect(contentBoxRect()); + } else { + repaintRect = contentBoxRect(); + } - // Tell any potential compositing layers that the image needs updating. - contentChanged(ImageChanged); + { + // FIXME: We should not be allowing repaint during layout. crbug.com/339584 + AllowPaintInvalidationScope scoper(frameView()); + invalidatePaintRectangle(repaintRect); } + + // Tell any potential compositing layers that the image needs updating. + contentChanged(ImageChanged); } void RenderImage::notifyFinished(Resource* newImage) @@ -361,15 +333,20 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOf // Only draw the alt text if it'll fit within the content box, // and only if it fits above the error image. TextRun textRun = RenderBlockFlow::constructTextRun(this, font, m_altText, style(), TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion, DefaultTextRunFlags | RespectDirection); - LayoutUnit textWidth = font.width(textRun); + float textWidth = font.width(textRun); TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.bounds = FloatRect(textRectOrigin, FloatSize(textWidth, fontMetrics.height())); context->setFillColor(resolveColor(CSSPropertyColor)); + if (textRun.direction() == RTL) { + int availableWidth = cWidth - static_cast<int>(paddingWidth); + textOrigin.move(availableWidth - ceilf(textWidth), 0); + } if (errorPictureDrawn) { if (usableWidth >= textWidth && fontMetrics.height() <= imageOffset.height()) - context->drawText(font, textRunPaintInfo, textOrigin); - } else if (usableWidth >= textWidth && usableHeight >= fontMetrics.height()) - context->drawText(font, textRunPaintInfo, textOrigin); + context->drawBidiText(font, textRunPaintInfo, textOrigin); + } else if (usableWidth >= textWidth && usableHeight >= fontMetrics.height()) { + context->drawBidiText(font, textRunPaintInfo, textOrigin); + } } } } else if (m_imageResource->hasImage() && cWidth > 0 && cHeight > 0) { @@ -413,21 +390,21 @@ void RenderImage::paintAreaElementFocusRing(PaintInfo& paintInfo) return; Element* focusedElement = document.focusedElement(); - if (!focusedElement || !isHTMLAreaElement(focusedElement)) + if (!isHTMLAreaElement(focusedElement)) return; - HTMLAreaElement* areaElement = toHTMLAreaElement(focusedElement); - if (areaElement->imageElement() != node()) + HTMLAreaElement& areaElement = toHTMLAreaElement(*focusedElement); + if (areaElement.imageElement() != node()) return; // Even if the theme handles focus ring drawing for entire elements, it won't do it for // an area within an image, so we don't call RenderTheme::supportsFocusRing here. - Path path = areaElement->computePath(this); + Path path = areaElement.computePath(this); if (path.isEmpty()) return; - RenderStyle* areaElementStyle = areaElement->computedStyle(); + RenderStyle* areaElementStyle = areaElement.computedStyle(); unsigned short outlineWidth = areaElementStyle->outlineWidth(); if (!outlineWidth) return; @@ -456,7 +433,7 @@ void RenderImage::areaElementFocusChanged(HTMLAreaElement* areaElement) repaintRect.moveBy(-absoluteContentBox().location()); repaintRect.inflate(outlineWidth); - repaintRectangle(repaintRect); + invalidatePaintRectangle(repaintRect); } void RenderImage::paintIntoRect(GraphicsContext* context, const LayoutRect& rect) @@ -469,13 +446,18 @@ void RenderImage::paintIntoRect(GraphicsContext* context, const LayoutRect& rect if (!img || img->isNull()) return; - HTMLImageElement* imageElt = (node() && node()->hasTagName(imgTag)) ? toHTMLImageElement(node()) : 0; + HTMLImageElement* imageElt = isHTMLImageElement(node()) ? toHTMLImageElement(node()) : 0; CompositeOperator compositeOperator = imageElt ? imageElt->compositeOperator() : CompositeSourceOver; Image* image = m_imageResource->image().get(); - bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, image, alignedRect.size()); + InterpolationQuality interpolationQuality = chooseInterpolationQuality(context, image, image, alignedRect.size()); + TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintImage", "data", InspectorPaintImageEvent::data(*this)); + // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. InspectorInstrumentation::willPaintImage(this); - context->drawImage(m_imageResource->image(alignedRect.width(), alignedRect.height()).get(), alignedRect, compositeOperator, shouldRespectImageOrientation(), useLowQualityScaling); + InterpolationQuality previousInterpolationQuality = context->imageInterpolationQuality(); + context->setImageInterpolationQuality(interpolationQuality); + context->drawImage(m_imageResource->image(alignedRect.width(), alignedRect.height()).get(), alignedRect, compositeOperator, shouldRespectImageOrientation()); + context->setImageInterpolationQuality(previousInterpolationQuality); InspectorInstrumentation::didPaintImage(this); } @@ -517,7 +499,11 @@ bool RenderImage::computeBackgroundIsKnownToBeObscured() { if (!hasBackground()) return false; - return foregroundIsKnownToBeOpaqueInRect(backgroundPaintedExtent(), 0); + + LayoutRect paintedExtent; + if (!getBackgroundPaintedExtent(paintedExtent)) + return false; + return foregroundIsKnownToBeOpaqueInRect(paintedExtent, 0); } LayoutUnit RenderImage::minimumReplacedHeight() const @@ -527,7 +513,7 @@ LayoutUnit RenderImage::minimumReplacedHeight() const HTMLMapElement* RenderImage::imageMap() const { - HTMLImageElement* i = node() && node()->hasTagName(imgTag) ? toHTMLImageElement(node()) : 0; + HTMLImageElement* i = isHTMLImageElement(node()) ? toHTMLImageElement(node()) : 0; return i ? i->treeScope().getImageMap(i->fastGetAttribute(usemapAttr)) : 0; } @@ -560,35 +546,22 @@ void RenderImage::updateAltText() if (!node()) return; - if (node()->hasTagName(inputTag)) + if (isHTMLInputElement(*node())) m_altText = toHTMLInputElement(node())->altText(); - else if (node()->hasTagName(imgTag)) + else if (isHTMLImageElement(*node())) m_altText = toHTMLImageElement(node())->altText(); } void RenderImage::layout() { - LayoutRectRecorder recorder(*this); RenderReplaced::layout(); updateInnerContentRect(); } -void RenderImage::didLayout(ResourceLoadPriorityOptimizer& optimizer) -{ - RenderReplaced::didLayout(optimizer); - updateImageLoadingPriority(optimizer); -} - -void RenderImage::didScroll(ResourceLoadPriorityOptimizer& optimizer) -{ - RenderReplaced::didScroll(optimizer); - updateImageLoadingPriority(optimizer); -} - -void RenderImage::updateImageLoadingPriority(ResourceLoadPriorityOptimizer& optimizer) +bool RenderImage::updateImageLoadingPriorities() { if (!m_imageResource || !m_imageResource->cachedImage() || m_imageResource->cachedImage()->isLoaded()) - return; + return false; LayoutRect viewBounds = viewRect(); LayoutRect objectBounds = absoluteContentBox(); @@ -604,20 +577,28 @@ void RenderImage::updateImageLoadingPriority(ResourceLoadPriorityOptimizer& opti ResourceLoadPriorityOptimizer::VisibilityStatus status = isVisible ? ResourceLoadPriorityOptimizer::Visible : ResourceLoadPriorityOptimizer::NotVisible; - optimizer.notifyImageResourceVisibility(m_imageResource->cachedImage(), status); + LayoutRect screenArea; + if (!objectBounds.isEmpty()) { + screenArea = viewBounds; + screenArea.intersect(objectBounds); + } + + ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->notifyImageResourceVisibility(m_imageResource->cachedImage(), status, screenArea); + + return true; } -void RenderImage::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const +void RenderImage::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const { - RenderReplaced::computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); + RenderReplaced::computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio); // 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 = isOutOfFlowPositioned() ? container() : this->containingBlock(); if (containingBlock->isBox()) { RenderBox* box = toRenderBox(containingBlock); - intrinsicSize.setWidth(box->availableLogicalWidth()); - intrinsicSize.setHeight(box->availableLogicalHeight(IncludeMarginBorderPadding)); + intrinsicSize.setWidth(box->availableLogicalWidth().toFloat()); + intrinsicSize.setHeight(box->availableLogicalHeight(IncludeMarginBorderPadding).toFloat()); } } // Don't compute an intrinsic ratio to preserve historical WebKit behavior if we're painting alt text and/or a broken image. diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderImage.h b/chromium/third_party/WebKit/Source/core/rendering/RenderImage.h index d7e67f0c7e3..0313703b8c7 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderImage.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderImage.h @@ -67,32 +67,28 @@ public: protected: virtual bool needsPreferredWidthsRecalculation() const OVERRIDE FINAL; virtual RenderBox* embeddedContentBox() const OVERRIDE FINAL; - virtual void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const OVERRIDE FINAL; + virtual void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const OVERRIDE FINAL; - virtual void styleDidChange(StyleDifference, const RenderStyle*) OVERRIDE FINAL; - - virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) OVERRIDE; void paintIntoRect(GraphicsContext*, const LayoutRect&); virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE FINAL; - virtual void layout(); - virtual void didLayout(ResourceLoadPriorityOptimizer&); - virtual void didScroll(ResourceLoadPriorityOptimizer&); - void updateImageLoadingPriority(ResourceLoadPriorityOptimizer&); + virtual void layout() OVERRIDE; + virtual bool updateImageLoadingPriorities() OVERRIDE FINAL; - virtual void intrinsicSizeChanged() + virtual void intrinsicSizeChanged() OVERRIDE { if (m_imageResource) imageChanged(m_imageResource->imagePtr()); } private: - virtual const char* renderName() const { return "RenderImage"; } + virtual const char* renderName() const OVERRIDE { return "RenderImage"; } - virtual bool isImage() const { return true; } + virtual bool isImage() const OVERRIDE { return true; } virtual bool isRenderImage() const OVERRIDE FINAL { return true; } - virtual void paintReplaced(PaintInfo&, const LayoutPoint&); + virtual void paintReplaced(PaintInfo&, const LayoutPoint&) OVERRIDE; virtual bool foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const OVERRIDE FINAL; virtual bool computeBackgroundIsKnownToBeObscured() OVERRIDE FINAL; @@ -105,8 +101,8 @@ private: virtual bool boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance, InlineFlowBox*) const OVERRIDE FINAL; IntSize imageSizeForError(ImageResource*) const; - void imageDimensionsChanged(bool imageSizeChanged, const IntRect* = 0); - bool updateIntrinsicSizeIfNeeded(const LayoutSize&, bool imageSizeChanged); + void repaintOrMarkForLayout(bool imageSizeChanged, const IntRect* = 0); + void updateIntrinsicSizeIfNeeded(const LayoutSize&); // Update the size of the image to be rendered. Object-fit may cause this to be different from the CSS box's content rect. void updateInnerContentRect(); @@ -115,7 +111,6 @@ private: // Text to display as long as the image isn't available. String m_altText; OwnPtr<RenderImageResource> m_imageResource; - bool m_needsToSetSizeForAltText; bool m_didIncrementVisuallyNonEmptyPixelCount; bool m_isGeneratedContent; float m_imageDevicePixelRatio; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderImageResource.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderImageResource.cpp index 12ab7231776..79fd0804e73 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderImageResource.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderImageResource.cpp @@ -87,7 +87,7 @@ void RenderImageResource::resetAnimation() image()->resetAnimation(); if (!m_renderer->needsLayout()) - m_renderer->repaint(); + m_renderer->paintInvalidationForWholeRenderer(); } void RenderImageResource::setContainerSizeForRenderer(const IntSize& imageContainerSize) @@ -97,11 +97,6 @@ void RenderImageResource::setContainerSizeForRenderer(const IntSize& imageContai m_cachedImage->setContainerSizeForRenderer(m_renderer, imageContainerSize, m_renderer->style()->effectiveZoom()); } -Image* RenderImageResource::nullImage() -{ - return Image::nullImage(); -} - LayoutSize RenderImageResource::getImageSize(float multiplier, ImageResource::SizeType type) const { if (!m_cachedImage) diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderImageResource.h b/chromium/third_party/WebKit/Source/core/rendering/RenderImageResource.h index cae42e2eb03..2850d72ba5b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderImageResource.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderImageResource.h @@ -29,8 +29,6 @@ #include "core/fetch/ImageResource.h" #include "core/fetch/ResourcePtr.h" #include "core/rendering/style/StyleImage.h" -#include "platform/geometry/LayoutSize.h" -#include "platform/graphics/Image.h" namespace WebCore { @@ -55,7 +53,10 @@ public: void resetAnimation(); - virtual PassRefPtr<Image> image(int /* width */ = 0, int /* height */ = 0) const { return m_cachedImage ? m_cachedImage->imageForRenderer(m_renderer) : nullImage(); } + virtual PassRefPtr<Image> image(int /* width */ = 0, int /* height */ = 0) const + { + return m_cachedImage ? m_cachedImage->imageForRenderer(m_renderer) : Image::nullImage(); + } virtual bool errorOccurred() const { return m_cachedImage && m_cachedImage->errorOccurred(); } virtual void setContainerSizeForRenderer(const IntSize&); @@ -74,7 +75,6 @@ protected: ResourcePtr<ImageResource> m_cachedImage; private: - static Image* nullImage(); LayoutSize getImageSize(float multiplier, ImageResource::SizeType) const; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderImageResourceStyleImage.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderImageResourceStyleImage.cpp index 5e0fff78319..eded16a0240 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderImageResourceStyleImage.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderImageResourceStyleImage.cpp @@ -65,7 +65,7 @@ PassRefPtr<Image> RenderImageResourceStyleImage::image(int width, int height) co { // Generated content may trigger calls to image() while we're still pending, don't assert but gracefully exit. if (m_styleImage->isPendingImage()) - return 0; + return nullptr; return m_styleImage->image(m_renderer, IntSize(width, height)); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderImageResourceStyleImage.h b/chromium/third_party/WebKit/Source/core/rendering/RenderImageResourceStyleImage.h index 6844e2a5811..098cc634acb 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderImageResourceStyleImage.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderImageResourceStyleImage.h @@ -34,7 +34,7 @@ namespace WebCore { class RenderObject; -class RenderImageResourceStyleImage : public RenderImageResource { +class RenderImageResourceStyleImage FINAL : public RenderImageResource { public: virtual ~RenderImageResourceStyleImage(); @@ -42,22 +42,22 @@ public: { return adoptPtr(new RenderImageResourceStyleImage(styleImage)); } - virtual void initialize(RenderObject*); - virtual void shutdown(); + virtual void initialize(RenderObject*) OVERRIDE; + virtual void shutdown() OVERRIDE; - virtual bool hasImage() const { return true; } - virtual PassRefPtr<Image> image(int width = 0, int height = 0) const; - virtual bool errorOccurred() const { return m_styleImage->errorOccurred(); } + virtual bool hasImage() const OVERRIDE { return true; } + virtual PassRefPtr<Image> image(int width = 0, int height = 0) const OVERRIDE; + virtual bool errorOccurred() const OVERRIDE { return m_styleImage->errorOccurred(); } - virtual void setContainerSizeForRenderer(const IntSize&); - virtual bool usesImageContainerSize() const { return m_styleImage->usesImageContainerSize(); } - virtual bool imageHasRelativeWidth() const { return m_styleImage->imageHasRelativeWidth(); } - virtual bool imageHasRelativeHeight() const { return m_styleImage->imageHasRelativeHeight(); } + virtual void setContainerSizeForRenderer(const IntSize&) OVERRIDE; + virtual bool usesImageContainerSize() const OVERRIDE { return m_styleImage->usesImageContainerSize(); } + virtual bool imageHasRelativeWidth() const OVERRIDE { return m_styleImage->imageHasRelativeWidth(); } + virtual bool imageHasRelativeHeight() const OVERRIDE { return m_styleImage->imageHasRelativeHeight(); } virtual LayoutSize imageSize(float multiplier) const OVERRIDE { return m_styleImage->imageSize(m_renderer, multiplier); } virtual LayoutSize intrinsicSize(float multiplier) const OVERRIDE { return m_styleImage->imageSize(m_renderer, multiplier); } - virtual WrappedImagePtr imagePtr() const { return m_styleImage->data(); } + virtual WrappedImagePtr imagePtr() const OVERRIDE { return m_styleImage->data(); } private: RenderImageResourceStyleImage(StyleImage*); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderInline.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderInline.cpp index bd82486d441..80664b5e3b1 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderInline.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderInline.cpp @@ -29,7 +29,6 @@ #include "core/rendering/GraphicsContextAnnotator.h" #include "core/rendering/HitTestResult.h" #include "core/rendering/InlineTextBox.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/RenderBlock.h" #include "core/rendering/RenderFlowThread.h" #include "core/rendering/RenderFullScreen.h" @@ -62,7 +61,7 @@ RenderInline* RenderInline::createAnonymous(Document* document) void RenderInline::willBeDestroyed() { -#if !ASSERT_DISABLED +#if ASSERT_ENABLED // Make sure we do not retain "this" in the continuation outline table map of our containing blocks. if (parent() && style()->visibility() == VISIBLE && hasOutline()) { bool containingBlockPaintsContinuationOutline = continuation() || isInlineElementContinuation(); @@ -194,7 +193,7 @@ void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldSt bool alwaysCreateLineBoxes = hasSelfPaintingLayer() || hasBoxDecorations() || newStyle->hasPadding() || newStyle->hasMargin() || hasOutline(); if (oldStyle && alwaysCreateLineBoxes) { dirtyLineBoxes(false); - setNeedsLayout(); + setNeedsLayoutAndFullPaintInvalidation(); } m_alwaysCreateLineBoxes = alwaysCreateLineBoxes; } @@ -210,14 +209,12 @@ void RenderInline::updateAlwaysCreateLineBoxes(bool fullLayout) RenderStyle* parentStyle = parent()->style(); RenderInline* parentRenderInline = parent()->isRenderInline() ? toRenderInline(parent()) : 0; bool checkFonts = document().inNoQuirksMode(); - RenderFlowThread* flowThread = flowThreadContainingBlock(); bool alwaysCreateLineBoxes = (parentRenderInline && parentRenderInline->alwaysCreateLineBoxes()) || (parentRenderInline && parentStyle->verticalAlign() != BASELINE) || style()->verticalAlign() != BASELINE || style()->textEmphasisMark() != TextEmphasisMarkNone || (checkFonts && (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(style()->font().fontMetrics()) - || parentStyle->lineHeight() != style()->lineHeight())) - || (flowThread && flowThread->hasRegionsWithStyling()); + || parentStyle->lineHeight() != style()->lineHeight())); if (!alwaysCreateLineBoxes && checkFonts && document().styleEngine()->usesFirstLineRules()) { // Have to check the first line style as well. @@ -283,7 +280,7 @@ RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild RenderBoxModelObject* last = this; while (curr) { if (beforeChild && beforeChild->parent() == curr) { - if (curr->firstChild() == beforeChild) + if (curr->slowFirstChild() == beforeChild) return last; return curr; } @@ -293,7 +290,7 @@ RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild curr = nextContinuation(curr); } - if (!beforeChild && !last->firstChild()) + if (!beforeChild && !last->slowFirstChild()) return nextToLast; return last; } @@ -327,7 +324,7 @@ void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderOb RenderBoxModelObject::addChild(newChild, beforeChild); - newChild->setNeedsLayoutAndPrefWidthsRecalc(); + newChild->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } RenderInline* RenderInline::clone() const @@ -351,7 +348,7 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, // that renderer is wrapped in a RenderFullScreen, so |this| is not its // parent. Since the splitting logic expects |this| to be the parent, set // |beforeChild| to be the RenderFullScreen. - if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExists(&document())) { + if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExists(document())) { const Element* fullScreenElement = fullscreen->webkitCurrentFullScreenElement(); if (fullScreenElement && beforeChild && beforeChild->node() == fullScreenElement) beforeChild = fullscreen->fullScreenRenderer(); @@ -364,7 +361,7 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, RenderObject* tmp = o; o = tmp->nextSibling(); cloneInline->addChildIgnoringContinuation(children()->removeChildNode(this, tmp), 0); - tmp->setNeedsLayoutAndPrefWidthsRecalc(); + tmp->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } // Hook |clone| up as the continuation of the middle block. @@ -405,7 +402,7 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, RenderObject* tmp = o; o = tmp->nextSibling(); cloneInline->addChildIgnoringContinuation(inlineCurr->children()->removeChildNode(curr, tmp), 0); - tmp->setNeedsLayoutAndPrefWidthsRecalc(); + tmp->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } } @@ -466,7 +463,7 @@ void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox RenderObject* no = o; o = no->nextSibling(); pre->children()->appendChildNode(pre, block->children()->removeChildNode(block, no)); - no->setNeedsLayoutAndPrefWidthsRecalc(); + no->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } } @@ -481,9 +478,9 @@ void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox // Always just do a full layout in order to ensure that line boxes (especially wrappers for images) // get deleted properly. Because objects moves from the pre block into the post block, we want to // make new line boxes instead of leaving the old line boxes around. - pre->setNeedsLayoutAndPrefWidthsRecalc(); - block->setNeedsLayoutAndPrefWidthsRecalc(); - post->setNeedsLayoutAndPrefWidthsRecalc(); + pre->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); + block->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); + post->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild) @@ -560,13 +557,13 @@ void RenderInline::generateCulledLineBoxRects(GeneratorContext& yield, const Ren if (curr->isBox()) { RenderBox* currBox = toRenderBox(curr); if (currBox->inlineBoxWrapper()) { - RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root(); - int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent()); - int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height(); + RootInlineBox& rootBox = currBox->inlineBoxWrapper()->root(); + int logicalTop = rootBox.logicalTop() + (rootBox.renderer().style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent()); + int logicalHeight = container->style(rootBox.isFirstLineStyle())->font().fontMetrics().height(); if (isHorizontal) - yield(FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginWidth(), logicalHeight)); + yield(FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, (currBox->width() + currBox->marginWidth()).toFloat(), logicalHeight)); else - yield(FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginHeight())); + yield(FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, (currBox->height() + currBox->marginHeight()).toFloat())); } } else if (curr->isRenderInline()) { // If the child doesn't need line boxes either, then we can recur. @@ -575,9 +572,9 @@ void RenderInline::generateCulledLineBoxRects(GeneratorContext& yield, const Ren currInline->generateCulledLineBoxRects(yield, container); else { for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) { - RootInlineBox* rootBox = childLine->root(); - int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent()); - int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height(); + RootInlineBox& rootBox = childLine->root(); + int logicalTop = rootBox.logicalTop() + (rootBox.renderer().style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent()); + int logicalHeight = container->style(rootBox.isFirstLineStyle())->font().fontMetrics().height(); if (isHorizontal) yield(FloatRect(childLine->x() - childLine->marginLogicalLeft(), logicalTop, @@ -593,9 +590,9 @@ void RenderInline::generateCulledLineBoxRects(GeneratorContext& yield, const Ren } else if (curr->isText()) { RenderText* currText = toRenderText(curr); for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) { - RootInlineBox* rootBox = childText->root(); - int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent()); - int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height(); + RootInlineBox& rootBox = childText->root(); + int logicalTop = rootBox.logicalTop() + (rootBox.renderer().style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent()); + int logicalHeight = container->style(rootBox.isFirstLineStyle())->font().fontMetrics().height(); if (isHorizontal) yield(FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight)); else @@ -696,8 +693,6 @@ static LayoutUnit computeMargin(const RenderInline* renderer, const Length& marg return margin.value(); if (margin.isPercent()) return minimumValueForLength(margin, max<LayoutUnit>(0, renderer->containingBlock()->availableLogicalWidth())); - if (margin.isViewportPercentage()) - return valueForLength(margin, 0, renderer->view()); return 0; } @@ -817,7 +812,7 @@ PositionWithAffinity RenderInline::positionForPoint(const LayoutPoint& point) RenderBoxModelObject* c = continuation(); while (c) { RenderBox* contBlock = c->isInline() ? c->containingBlock() : toRenderBlock(c); - if (c->isInline() || c->firstChild()) + if (c->isInline() || c->slowFirstChild()) return c->positionForPoint(parentBlockPoint - contBlock->locationOffset()); c = toRenderBlock(c)->inlineElementContinuation(); } @@ -984,12 +979,12 @@ LayoutRect RenderInline::linesVisualOverflowBoundingBox() const logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow()); } - RootInlineBox* firstRootBox = firstLineBox()->root(); - RootInlineBox* lastRootBox = lastLineBox()->root(); + RootInlineBox& firstRootBox = firstLineBox()->root(); + RootInlineBox& lastRootBox = lastLineBox()->root(); - LayoutUnit logicalTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox->lineTop()); + LayoutUnit logicalTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox.lineTop()); LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide; - LayoutUnit logicalHeight = lastLineBox()->logicalBottomVisualOverflow(lastRootBox->lineBottom()) - logicalTop; + LayoutUnit logicalHeight = lastLineBox()->logicalBottomVisualOverflow(lastRootBox.lineBottom()) - logicalTop; LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight); if (!style()->isHorizontalWritingMode()) @@ -997,9 +992,9 @@ LayoutRect RenderInline::linesVisualOverflowBoundingBox() const return rect; } -LayoutRect RenderInline::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const +LayoutRect RenderInline::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const { - ASSERT(!view() || !view()->layoutStateEnabled() || LayoutRectRecorder::shouldRecordLayoutRects()); + ASSERT(!view() || !view()->layoutStateCachedOffsetsEnabled()); if (!firstLineBoxIncludingCulling() && !continuation()) return LayoutRect(); @@ -1012,7 +1007,7 @@ LayoutRect RenderInline::clippedOverflowRectForRepaint(const RenderLayerModelObj RenderBlock* cb = containingBlock(); for (const RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb; inlineFlow = inlineFlow->parent()) { - if (inlineFlow == repaintContainer) { + if (inlineFlow == paintInvalidationContainer) { hitRepaintContainer = true; break; } @@ -1032,51 +1027,51 @@ LayoutRect RenderInline::clippedOverflowRectForRepaint(const RenderLayerModelObj if (cb->hasOverflowClip()) cb->applyCachedClipAndScrollOffsetForRepaint(repaintRect); - cb->computeRectForRepaint(repaintContainer, repaintRect); + cb->mapRectToPaintInvalidationBacking(paintInvalidationContainer, repaintRect); if (outlineSize) { for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { if (!curr->isText()) - repaintRect.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineSize)); + repaintRect.unite(curr->rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineSize)); } if (continuation() && !continuation()->isInline() && continuation()->parent()) - repaintRect.unite(continuation()->rectWithOutlineForRepaint(repaintContainer, outlineSize)); + repaintRect.unite(continuation()->rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineSize)); } return repaintRect; } -LayoutRect RenderInline::rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const +LayoutRect RenderInline::rectWithOutlineForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, LayoutUnit outlineWidth) const { - LayoutRect r(RenderBoxModelObject::rectWithOutlineForRepaint(repaintContainer, outlineWidth)); + LayoutRect r(RenderBoxModelObject::rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineWidth)); for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { if (!curr->isText()) - r.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineWidth)); + r.unite(curr->rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineWidth)); } return r; } -void RenderInline::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const +void RenderInline::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, bool fixed) const { if (RenderView* v = view()) { // LayoutState is only valid for root-relative repainting - if (v->layoutStateEnabled() && !repaintContainer) { + if (v->canMapUsingLayoutStateForContainer(paintInvalidationContainer)) { LayoutState* layoutState = v->layoutState(); if (style()->hasInFlowPosition() && layer()) rect.move(layer()->offsetForInFlowPosition()); - rect.move(layoutState->m_paintOffset); - if (layoutState->m_clipped) - rect.intersect(layoutState->m_clipRect); + rect.move(layoutState->paintOffset()); + if (layoutState->isClipped()) + rect.intersect(layoutState->clipRect()); return; } } - if (repaintContainer == this) + if (paintInvalidationContainer == this) return; bool containerSkipped; - RenderObject* o = container(repaintContainer, &containerSkipped); + RenderObject* o = container(paintInvalidationContainer, &containerSkipped); if (!o) return; @@ -1111,16 +1106,16 @@ void RenderInline::computeRectForRepaint(const RenderLayerModelObject* repaintCo } if (containerSkipped) { - // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates. - LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o); + // If the paintInvalidationContainer is below o, then we need to map the rect into paintInvalidationContainer's coordinates. + LayoutSize containerOffset = paintInvalidationContainer->offsetFromAncestorContainer(o); rect.move(-containerOffset); return; } - o->computeRectForRepaint(repaintContainer, rect, fixed); + o->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, fixed); } -LayoutSize RenderInline::offsetFromContainer(RenderObject* container, const LayoutPoint& point, bool* offsetDependsOnPoint) const +LayoutSize RenderInline::offsetFromContainer(const RenderObject* container, const LayoutPoint& point, bool* offsetDependsOnPoint) const { ASSERT(container == this->container()); @@ -1128,7 +1123,7 @@ LayoutSize RenderInline::offsetFromContainer(RenderObject* container, const Layo if (isInFlowPositioned()) offset += offsetForInFlowPosition(); - container->adjustForColumns(offset, point); + offset += container->columnOffset(point); if (container->hasOverflowClip()) offset -= toRenderBox(container)->scrolledContentOffset(); @@ -1148,9 +1143,9 @@ void RenderInline::mapLocalToContainer(const RenderLayerModelObject* repaintCont return; if (RenderView *v = view()) { - if (v->layoutStateEnabled() && !repaintContainer) { + if (v->canMapUsingLayoutStateForContainer(repaintContainer)) { LayoutState* layoutState = v->layoutState(); - LayoutSize offset = layoutState->m_paintOffset; + LayoutSize offset = layoutState->paintOffset(); if (style()->hasInFlowPosition() && layer()) offset += layer()->offsetForInFlowPosition(); transformState.move(offset); @@ -1250,16 +1245,16 @@ void RenderInline::dirtyLineBoxes(bool fullLayout) if (curr->isBox() && !curr->needsLayout()) { RenderBox* currBox = toRenderBox(curr); if (currBox->inlineBoxWrapper()) - currBox->inlineBoxWrapper()->root()->markDirty(); + currBox->inlineBoxWrapper()->root().markDirty(); } else if (!curr->selfNeedsLayout()) { if (curr->isRenderInline()) { RenderInline* currInline = toRenderInline(curr); for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) - childLine->root()->markDirty(); + childLine->root().markDirty(); } else if (curr->isText()) { RenderText* currText = toRenderText(curr); for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) - childText->root()->markDirty(); + childText->root().markDirty(); } } } @@ -1274,7 +1269,7 @@ void RenderInline::deleteLineBoxTree() InlineFlowBox* RenderInline::createInlineFlowBox() { - return new InlineFlowBox(this); + return new InlineFlowBox(*this); } InlineFlowBox* RenderInline::createAndAppendInlineFlowBox() @@ -1290,10 +1285,10 @@ LayoutUnit RenderInline::lineHeight(bool firstLine, LineDirectionMode /*directio if (firstLine && document().styleEngine()->usesFirstLineRules()) { RenderStyle* s = style(firstLine); if (s != style()) - return s->computedLineHeight(view()); + return s->computedLineHeight(); } - return style()->computedLineHeight(view()); + return style()->computedLineHeight(); } int RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const @@ -1303,7 +1298,7 @@ int RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, Li return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2; } -LayoutSize RenderInline::offsetForInFlowPositionedInline(const RenderBox* child) const +LayoutSize RenderInline::offsetForInFlowPositionedInline(const RenderBox& child) const { // FIXME: This function isn't right with mixed writing modes. @@ -1326,18 +1321,18 @@ LayoutSize RenderInline::offsetForInFlowPositionedInline(const RenderBox* child) blockPosition = layer()->staticBlockPosition(); } - if (!child->style()->hasStaticInlinePosition(style()->isHorizontalWritingMode())) + if (!child.style()->hasStaticInlinePosition(style()->isHorizontalWritingMode())) logicalOffset.setWidth(inlinePosition); // This is not terribly intuitive, but we have to match other browsers. Despite being a block display type inside // an inline, we still keep our x locked to the left of the relative positioned inline. Arguably the correct // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers // do. - else if (!child->style()->isOriginalDisplayInlineType()) + else if (!child.style()->isOriginalDisplayInlineType()) // Avoid adding in the left border/padding of the containing block twice. Subtract it out. - logicalOffset.setWidth(inlinePosition - child->containingBlock()->borderAndPaddingLogicalLeft()); + logicalOffset.setWidth(inlinePosition - child.containingBlock()->borderAndPaddingLogicalLeft()); - if (!child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode())) + if (!child.style()->hasStaticBlockPosition(style()->isHorizontalWritingMode())) logicalOffset.setHeight(blockPosition); return style()->isHorizontalWritingMode() ? logicalOffset : logicalOffset.transposedSize(); @@ -1349,7 +1344,7 @@ void RenderInline::imageChanged(WrappedImagePtr, const IntRect*) return; // FIXME: We can do better. - repaint(); + paintInvalidationForWholeRenderer(); } void RenderInline::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer) @@ -1357,19 +1352,12 @@ void RenderInline::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& AbsoluteRectsGeneratorContext context(rects, additionalOffset); generateLineBoxRects(context); - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - if (!curr->isText() && !curr->isListMarker()) { - FloatPoint pos(additionalOffset); - // FIXME: This doesn't work correctly with transforms. - if (curr->hasLayer()) - pos = curr->localToContainerPoint(FloatPoint(), paintContainer); - else if (curr->isBox()) - pos.move(toRenderBox(curr)->locationOffset()); - curr->addFocusRingRects(rects, flooredIntPoint(pos), paintContainer); - } - } + addChildFocusRingRects(rects, additionalOffset, paintContainer); if (continuation()) { + // If the continuation doesn't paint into the same container, let its repaint container handle it. + if (paintContainer != continuation()->containerForPaintInvalidation()) + return; if (continuation()->isInline()) continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + continuation()->containingBlock()->location() - containingBlock()->location()), paintContainer); else @@ -1428,9 +1416,9 @@ void RenderInline::paintOutline(PaintInfo& paintInfo, const LayoutPoint& paintOf rects.append(LayoutRect()); for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { - RootInlineBox* root = curr->root(); - LayoutUnit top = max<LayoutUnit>(root->lineTop(), curr->logicalTop()); - LayoutUnit bottom = min<LayoutUnit>(root->lineBottom(), curr->logicalBottom()); + RootInlineBox& root = curr->root(); + LayoutUnit top = max<LayoutUnit>(root.lineTop(), curr->logicalTop()); + LayoutUnit bottom = min<LayoutUnit>(root.lineBottom(), curr->logicalBottom()); rects.append(LayoutRect(curr->x(), top, curr->logicalWidth(), bottom - top)); } rects.append(LayoutRect()); @@ -1465,6 +1453,8 @@ void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, const L LayoutSize(thisline.width() + offset, thisline.height() + offset)); IntRect pixelSnappedBox = pixelSnappedIntRect(box); + if (pixelSnappedBox.width() < 0 || pixelSnappedBox.height() < 0) + return; IntRect pixelSnappedLastLine = pixelSnappedIntRect(paintOffset.x() + lastline.x(), 0, lastline.width(), 0); IntRect pixelSnappedNextLine = pixelSnappedIntRect(paintOffset.x() + nextline.x(), 0, nextline.width(), 0); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderInline.h b/chromium/third_party/WebKit/Source/core/rendering/RenderInline.h index c69f0258daa..c2710ab5143 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderInline.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderInline.h @@ -23,14 +23,13 @@ #ifndef RenderInline_h #define RenderInline_h +#include "core/animation/ActiveAnimations.h" #include "core/rendering/InlineFlowBox.h" #include "core/rendering/RenderBoxModelObject.h" #include "core/rendering/RenderLineBoxList.h" namespace WebCore { -class Position; - class RenderInline : public RenderBoxModelObject { public: explicit RenderInline(Element*); @@ -40,7 +39,11 @@ public: RenderObject* firstChild() const { ASSERT(children() == virtualChildren()); return children()->firstChild(); } RenderObject* lastChild() const { ASSERT(children() == virtualChildren()); return children()->lastChild(); } - virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); + // If you have a RenderInline, use firstChild or lastChild instead. + void slowFirstChild() const WTF_DELETED_FUNCTION; + void slowLastChild() const WTF_DELETED_FUNCTION; + + virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0) OVERRIDE; Element* node() const { return toElement(RenderBoxModelObject::node()); } @@ -54,9 +57,9 @@ public: virtual LayoutUnit marginEnd(const RenderStyle* otherStyle = 0) const OVERRIDE FINAL; virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const OVERRIDE FINAL; - virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; + virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const OVERRIDE; - virtual LayoutSize offsetFromContainer(RenderObject*, const LayoutPoint&, bool* offsetDependsOnPoint = 0) const OVERRIDE FINAL; + virtual LayoutSize offsetFromContainer(const RenderObject*, const LayoutPoint&, bool* offsetDependsOnPoint = 0) const OVERRIDE FINAL; IntRect linesBoundingBox() const; LayoutRect linesVisualOverflowBoundingBox() const; @@ -79,7 +82,7 @@ public: virtual void updateDragState(bool dragOn) OVERRIDE FINAL; - LayoutSize offsetForInFlowPositionedInline(const RenderBox* child) const; + LayoutSize offsetForInFlowPositionedInline(const RenderBox& child) const; virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) OVERRIDE FINAL; void paintOutline(PaintInfo&, const LayoutPoint&); @@ -96,7 +99,7 @@ public: bool hitTestCulledInline(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset); protected: - virtual void willBeDestroyed(); + virtual void willBeDestroyed() OVERRIDE; virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; @@ -108,7 +111,7 @@ private: const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } - virtual const char* renderName() const; + virtual const char* renderName() const OVERRIDE; virtual bool isRenderInline() const OVERRIDE FINAL { return true; } @@ -135,16 +138,16 @@ private: virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE FINAL; - virtual bool requiresLayer() const { return isInFlowPositioned() || createsGroup() || hasClipPath(); } + virtual LayerType layerTypeRequired() const OVERRIDE { return isInFlowPositioned() || createsGroup() || hasClipPath() || style()->shouldCompositeForCurrentAnimations() ? NormalLayer : NoLayer; } virtual LayoutUnit offsetLeft() const OVERRIDE FINAL; virtual LayoutUnit offsetTop() const OVERRIDE FINAL; virtual LayoutUnit offsetWidth() const OVERRIDE FINAL { return linesBoundingBox().width(); } virtual LayoutUnit offsetHeight() const OVERRIDE FINAL { return linesBoundingBox().height(); } - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE; - virtual LayoutRect rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const OVERRIDE FINAL; - virtual void computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect&, bool fixed) const OVERRIDE FINAL; + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const OVERRIDE; + virtual LayoutRect rectWithOutlineForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, LayoutUnit outlineWidth) const OVERRIDE FINAL; + virtual void mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect&, bool fixed) const OVERRIDE FINAL; virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderInputSpeech.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderInputSpeech.cpp deleted file mode 100644 index 85134417040..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderInputSpeech.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2010 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: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT - * OWNER 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(INPUT_SPEECH) -#include "core/rendering/RenderInputSpeech.h" - -#include "core/html/shadow/TextControlInnerElements.h" -#include "core/rendering/PaintInfo.h" -#include "core/rendering/RenderBox.h" -#include "platform/graphics/GraphicsContext.h" - -namespace WebCore { - -static const float defaultControlFontPixelSize = 13; -static const float defaultSpeechButtonSize = 16; -static const float minSpeechButtonSize = 8; -static const float maxSpeechButtonSize = 40; - -void RenderInputSpeech::adjustInputFieldSpeechButtonStyle(RenderStyle* style, Element*) -{ - // Scale the button size based on the font size. - float fontScale = style->fontSize() / defaultControlFontPixelSize; - int speechButtonSize = lroundf(std::min(std::max(minSpeechButtonSize, defaultSpeechButtonSize * fontScale), maxSpeechButtonSize)); - style->setWidth(Length(speechButtonSize, Fixed)); - style->setHeight(Length(speechButtonSize, Fixed)); -} - -bool RenderInputSpeech::paintInputFieldSpeechButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) -{ - Element* element = object->node()->isElementNode() ? toElement(object->node()) : 0; - if (!element || !element->isInputFieldSpeechButtonElement()) - return false; - - // Get the renderer of <input> element. - Node* input = object->node()->shadowHost(); - if (!input->renderer()->isBox()) - return false; - RenderBox* inputRenderBox = toRenderBox(input->renderer()); - LayoutRect inputContentBox = inputRenderBox->contentBoxRect(); - - // Make sure the scaled button stays square and will fit in its parent's box. - 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. - 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. - LayoutSize offsetFromInputRenderer = -(object->offsetFromAncestorContainer(inputRenderBox)); - // Move the rect into partRenderer's coords. - buttonRect.move(offsetFromInputRenderer); - // Account for the local drawing offset. - buttonRect.moveBy(rect.location()); - - DEFINE_STATIC_REF(Image, imageStateNormal, (Image::loadPlatformResource("inputSpeech"))); - DEFINE_STATIC_REF(Image, imageStateRecording, (Image::loadPlatformResource("inputSpeechRecording"))); - DEFINE_STATIC_REF(Image, imageStateWaiting, (Image::loadPlatformResource("inputSpeechWaiting"))); - - InputFieldSpeechButtonElement* speechButton = toInputFieldSpeechButtonElement(element); - Image* image = imageStateNormal; - if (speechButton->state() == InputFieldSpeechButtonElement::Recording) - image = imageStateRecording; - else if (speechButton->state() == InputFieldSpeechButtonElement::Recognizing) - image = imageStateWaiting; - paintInfo.context->drawImage(image, pixelSnappedIntRect(buttonRect)); - - return false; -} - -} // namespace WebCore - -#endif // ENABLE(INPUT_SPEECH) diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderInputSpeech.h b/chromium/third_party/WebKit/Source/core/rendering/RenderInputSpeech.h deleted file mode 100644 index e1d8c6e1ee8..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderInputSpeech.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2010 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: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT - * OWNER 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 RenderInputSpeech_h -#define RenderInputSpeech_h - -#if ENABLE(INPUT_SPEECH) - -namespace WebCore { - -struct PaintInfo; - -class Element; -class IntRect; -class RenderObject; -class RenderStyle; -class StyleResolver; - -class RenderInputSpeech { -public: - static void adjustInputFieldSpeechButtonStyle(RenderStyle*, Element*); - static bool paintInputFieldSpeechButton(RenderObject*, const PaintInfo&, const IntRect&); -}; - -} // namespace WebCore - -#endif -#endif // RenderInputSpeech_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayer.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderLayer.cpp index c3b8403215f..6b7ba1c904f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayer.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayer.cpp @@ -44,23 +44,20 @@ #include "config.h" #include "core/rendering/RenderLayer.h" -#include "CSSPropertyNames.h" -#include "HTMLNames.h" -#include "RuntimeEnabledFeatures.h" -#include "SVGNames.h" +#include "core/CSSPropertyNames.h" +#include "core/HTMLNames.h" #include "core/animation/ActiveAnimations.h" #include "core/css/PseudoStyleRequest.h" #include "core/dom/Document.h" #include "core/dom/shadow/ShadowRoot.h" -#include "core/html/HTMLFrameElement.h" -#include "core/frame/Frame.h" +#include "core/frame/DeprecatedScheduleStyleRecalcDuringLayout.h" #include "core/frame/FrameView.h" -#include "core/page/Page.h" +#include "core/frame/LocalFrame.h" #include "core/frame/Settings.h" -#include "core/frame/animation/AnimationController.h" +#include "core/html/HTMLFrameElement.h" +#include "core/page/Page.h" #include "core/page/scrolling/ScrollingCoordinator.h" #include "core/rendering/ColumnInfo.h" -#include "core/rendering/CompositedLayerMapping.h" #include "core/rendering/FilterEffectRenderer.h" #include "core/rendering/HitTestRequest.h" #include "core/rendering/HitTestResult.h" @@ -68,26 +65,25 @@ #include "core/rendering/RenderFlowThread.h" #include "core/rendering/RenderGeometryMap.h" #include "core/rendering/RenderInline.h" -#include "core/rendering/RenderLayerCompositor.h" #include "core/rendering/RenderReplica.h" #include "core/rendering/RenderScrollbar.h" #include "core/rendering/RenderScrollbarPart.h" #include "core/rendering/RenderTreeAsText.h" #include "core/rendering/RenderView.h" +#include "core/rendering/compositing/CompositedLayerMapping.h" +#include "core/rendering/compositing/RenderLayerCompositor.h" #include "core/rendering/svg/ReferenceFilterBuilder.h" #include "core/rendering/svg/RenderSVGResourceClipper.h" #include "platform/LengthFunctions.h" #include "platform/Partitions.h" +#include "platform/RuntimeEnabledFeatures.h" #include "platform/TraceEvent.h" #include "platform/geometry/FloatPoint3D.h" #include "platform/geometry/FloatRect.h" +#include "platform/geometry/TransformState.h" #include "platform/graphics/GraphicsContextStateSaver.h" #include "platform/graphics/filters/ReferenceFilter.h" #include "platform/graphics/filters/SourceGraphic.h" -#include "platform/graphics/filters/custom/CustomFilterGlobalContext.h" -#include "platform/graphics/filters/custom/CustomFilterOperation.h" -#include "platform/graphics/filters/custom/CustomFilterValidatedProgram.h" -#include "platform/graphics/filters/custom/ValidatedCustomFilterOperation.h" #include "platform/transforms/ScaleTransformOperation.h" #include "platform/transforms/TransformationMatrix.h" #include "platform/transforms/TranslateTransformOperation.h" @@ -99,19 +95,21 @@ using namespace std; namespace WebCore { +namespace { + +static CompositingQueryMode gCompositingQueryMode = + CompositingQueriesAreOnlyAllowedInCertainDocumentLifecyclePhases; + +} // namespace + using namespace HTMLNames; -RenderLayer::RenderLayer(RenderLayerModelObject* renderer) - : m_hasSelfPaintingLayerDescendant(false) +RenderLayer::RenderLayer(RenderLayerModelObject* renderer, LayerType type) + : m_layerType(type) + , m_hasSelfPaintingLayerDescendant(false) , m_hasSelfPaintingLayerDescendantDirty(false) - , m_hasOutOfFlowPositionedDescendant(false) - , m_hasOutOfFlowPositionedDescendantDirty(true) - , m_hasUnclippedDescendant(false) - , m_isUnclippedDescendant(false) , m_isRootLayer(renderer->isRenderView()) , m_usedTransparency(false) - , m_childLayerHasBlendMode(false) - , m_childLayerHasBlendModeStatusDirty(false) , m_visibleContentStatusDirty(true) , m_hasVisibleContent(false) , m_visibleDescendantStatusDirty(false) @@ -123,7 +121,13 @@ RenderLayer::RenderLayer(RenderLayerModelObject* renderer) , m_containsDirtyOverlayScrollbars(false) , m_canSkipRepaintRectsUpdateOnScroll(renderer->isTableCell()) , m_hasFilterInfo(false) - , m_blendMode(blink::WebBlendModeNormal) + , m_needsCompositingInputsUpdate(true) + , m_childNeedsCompositingInputsUpdate(true) + , m_hasCompositingDescendant(false) + , m_hasNonCompositedChild(false) + , m_shouldIsolateCompositedDescendants(false) + , m_lostGroupedMapping(false) + , m_viewportConstrainedNotCompositedReason(NoNotCompositedReason) , m_renderer(renderer) , m_parent(0) , m_previous(0) @@ -133,15 +137,18 @@ RenderLayer::RenderLayer(RenderLayerModelObject* renderer) , m_staticInlinePosition(0) , m_staticBlockPosition(0) , m_enclosingPaginationLayer(0) + , m_styleDeterminedCompositingReasons(CompositingReasonNone) + , m_compositingReasons(CompositingReasonNone) , m_groupedMapping(0) - , m_repainter(renderer) - , m_clipper(renderer) + , m_repainter(*renderer) + , m_clipper(*renderer) + , m_blendInfo(*renderer) { updateStackingNode(); m_isSelfPaintingLayer = shouldBeSelfPaintingLayer(); - if (!renderer->firstChild() && renderer->style()) { + if (!renderer->slowFirstChild() && renderer->style()) { m_visibleContentStatusDirty = false; m_hasVisibleContent = renderer->style()->visibility() == VISIBLE; } @@ -151,9 +158,6 @@ RenderLayer::RenderLayer(RenderLayerModelObject* renderer) RenderLayer::~RenderLayer() { - if (!m_renderer->documentBeingDestroyed()) - compositor()->removeOutOfFlowPositionedLayer(this); - if (renderer()->frame() && renderer()->frame()->page()) { if (ScrollingCoordinator* scrollingCoordinator = renderer()->frame()->page()->scrollingCoordinator()) scrollingCoordinator->willDestroyRenderLayer(this); @@ -161,6 +165,12 @@ RenderLayer::~RenderLayer() removeFilterInfoIfNeeded(); + if (groupedMapping()) { + DisableCompositingQueryAsserts disabler; + groupedMapping()->removeRenderLayerFromSquashingGraphicsLayer(this); + setGroupedMapping(0); + } + // Child layers will be deleted by their corresponding render objects, so // we don't need to delete them ourselves. @@ -169,8 +179,10 @@ RenderLayer::~RenderLayer() String RenderLayer::debugName() const { - if (isReflection()) + if (isReflection()) { + ASSERT(m_reflectionInfo); return m_reflectionInfo->debugName(); + } return renderer()->debugName(); } @@ -183,28 +195,38 @@ RenderLayerCompositor* RenderLayer::compositor() const void RenderLayer::contentChanged(ContentChangeType changeType) { - // This can get called when video becomes accelerated, so the layers may change. - if ((changeType == CanvasChanged || changeType == VideoChanged || changeType == FullScreenChanged) && compositor()->updateLayerCompositingState(this)) - compositor()->setCompositingLayersNeedRebuild(); + // updateLayerCompositingState will query compositingReasons for accelerated overflow scrolling. + // This is tripped by LayoutTests/compositing/content-changed-chicken-egg.html + DisableCompositingQueryAsserts disabler; + + if (changeType == CanvasChanged) + compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange); + + if (changeType == CanvasContextChanged) { + compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange); + + // Although we're missing test coverage, we need to call + // GraphicsLayer::setContentsToPlatformLayer with the new platform + // layer for this canvas. + // See http://crbug.com/349195 + if (hasCompositedLayerMapping()) + compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree); + } if (m_compositedLayerMapping) m_compositedLayerMapping->contentChanged(changeType); } -bool RenderLayer::canRender3DTransforms() const -{ - return compositor()->canRender3DTransforms(); -} - bool RenderLayer::paintsWithFilters() const { if (!renderer()->hasFilter()) return false; - if (compositingState() != PaintsIntoOwnBacking) - return true; - - if (!m_compositedLayerMapping || !m_compositedLayerMapping->canCompositeFilters()) + // https://code.google.com/p/chromium/issues/detail?id=343759 + DisableCompositingQueryAsserts disabler; + if (!m_compositedLayerMapping + || compositingState() != PaintsIntoOwnBacking + || !m_compositedLayerMapping->canCompositeFilters()) return true; return false; @@ -218,57 +240,43 @@ bool RenderLayer::requiresFullLayerImageForFilters() const return filter ? filter->hasFilterThatMovesPixels() : false; } -LayoutPoint RenderLayer::computeOffsetFromRoot(bool& hasLayerOffset) const +LayoutSize RenderLayer::subpixelAccumulation() const { - hasLayerOffset = true; - - if (!parent()) - return LayoutPoint(); - - // This is similar to root() but we check if an ancestor layer would - // prevent the optimization from working. - const RenderLayer* rootLayer = 0; - for (const RenderLayer* parentLayer = parent(); parentLayer; rootLayer = parentLayer, parentLayer = parentLayer->parent()) { - hasLayerOffset = parentLayer->canUseConvertToLayerCoords(); - if (!hasLayerOffset) - return LayoutPoint(); - } - ASSERT(rootLayer == root()); + return m_subpixelAccumulation; +} - LayoutPoint offset; - parent()->convertToLayerCoords(rootLayer, offset); - return offset; +void RenderLayer::setSubpixelAccumulation(const LayoutSize& size) +{ + m_subpixelAccumulation = size; } void RenderLayer::updateLayerPositionsAfterLayout(const RenderLayer* rootLayer, UpdateLayerPositionsFlags flags) { - RenderGeometryMap geometryMap(UseTransforms); - if (this != rootLayer) - geometryMap.pushMappingsToAncestor(parent(), 0); - updateLayerPositions(&geometryMap, flags); + TRACE_EVENT0("blink_rendering", "RenderLayer::updateLayerPositionsAfterLayout"); + + // FIXME: Remove incremental compositing updates after fixing the chicken/egg issues + // https://code.google.com/p/chromium/issues/detail?id=343756 + DisableCompositingQueryAsserts disabler; + updateLayerPositionRecursive(flags); } -void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLayerPositionsFlags flags) +void RenderLayer::updateLayerPositionRecursive(UpdateLayerPositionsFlags flags) { - updateLayerPosition(); // For relpositioned layers or non-positioned layers, - // we need to keep in sync, since we may have shifted relative - // to our parent layer. - if (geometryMap) - geometryMap->pushMappingsToAncestor(this, parent()); + if (updateLayerPosition()) + flags |= ForceMayNeedPaintInvalidation; + + if (flags & ForceMayNeedPaintInvalidation) + m_renderer->setMayNeedPaintInvalidation(true); // Clear our cached clip rect information. m_clipper.clearClipRects(); if (hasOverflowControls()) { - LayoutPoint offsetFromRoot; - if (geometryMap) - offsetFromRoot = LayoutPoint(geometryMap->absolutePoint(FloatPoint())); - else { - // FIXME: It looks suspicious to call convertToLayerCoords here - // as canUseConvertToLayerCoords may be true for an ancestor layer. - convertToLayerCoords(root(), offsetFromRoot); - } - scrollableArea()->positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot))); + // FIXME: We should figure out the right time to position the overflow controls. + // This call appears to be necessary to pass some layout test that use EventSender, + // presumably because the normal time to position the controls is during paint. We + // probably shouldn't position the overflow controls during paint either... + scrollableArea()->positionOverflowControls(IntSize()); } updateDescendantDependentFlags(); @@ -280,18 +288,13 @@ void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLay m_enclosingPaginationLayer = 0; } - repainter().repaintAfterLayout(geometryMap, flags & CheckForRepaint); + repainter().repaintAfterLayout(flags & CheckForRepaint); // Go ahead and update the reflection's position and size. if (m_reflectionInfo) m_reflectionInfo->reflection()->layout(); - // Clear the IsCompositingUpdateRoot flag once we've found the first compositing layer in this update. - bool isUpdateRoot = (flags & IsCompositingUpdateRoot); - if (hasCompositedLayerMapping()) - flags &= ~IsCompositingUpdateRoot; - - if (useRegionBasedColumns() && renderer()->isInFlowRenderFlowThread()) { + if (useRegionBasedColumns() && renderer()->isRenderFlowThread()) { updatePagination(); flags |= UpdatePagination; } @@ -300,19 +303,15 @@ void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLay flags |= UpdatePagination; for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) - child->updateLayerPositions(geometryMap, flags); + child->updateLayerPositionRecursive(flags); - if ((flags & UpdateCompositingLayers) && hasCompositedLayerMapping()) { - CompositedLayerMapping::UpdateAfterLayoutFlags updateFlags = CompositedLayerMapping::CompositingChildrenOnly; - if (flags & NeedsFullRepaintInBacking) - updateFlags |= CompositedLayerMapping::NeedsFullRepaint; - if (isUpdateRoot) - updateFlags |= CompositedLayerMapping::IsUpdateRoot; - compositedLayerMapping()->updateAfterLayout(updateFlags); + // FIXME: why isn't FrameView just calling RenderLayerCompositor::repaintCompositedLayers? Does it really impact + // performance? + if ((flags & NeedsFullRepaintInBacking) && hasCompositedLayerMapping() && !compositedLayerMapping()->paintsIntoCompositedAncestor()) { + compositedLayerMapping()->setContentsNeedDisplay(); + // This code is called when the FrameView wants to repaint the entire frame. This includes squashing content. + compositedLayerMapping()->setSquashingContentsNeedDisplay(); } - - if (geometryMap) - geometryMap->popMappingsToAncestor(parent()); } void RenderLayer::setAncestorChainHasSelfPaintingLayerDescendant() @@ -339,52 +338,6 @@ void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus() } } -void RenderLayer::setAncestorChainHasOutOfFlowPositionedDescendant() -{ - for (RenderLayer* layer = this; layer; layer = layer->parent()) { - if (!layer->m_hasOutOfFlowPositionedDescendantDirty && layer->hasOutOfFlowPositionedDescendant()) - break; - - layer->setHasOutOfFlowPositionedDescendantDirty(false); - layer->setHasOutOfFlowPositionedDescendant(true); - } -} - -void RenderLayer::dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus() -{ - for (RenderLayer* layer = this; layer; layer = layer->parent()) { - layer->setHasOutOfFlowPositionedDescendantDirty(true); - - // We may or may not have an unclipped descendant. If we do, we'll reset - // this to true the next time composited scrolling state is updated. - layer->setHasUnclippedDescendant(false); - - // If we have reached an out of flow positioned layer, we know our parent should have an out-of-flow positioned descendant. - // In this case, there is no need to dirty our ancestors further. - if (layer->renderer()->isOutOfFlowPositioned()) { - ASSERT(!parent() || parent()->m_hasOutOfFlowPositionedDescendantDirty || parent()->hasOutOfFlowPositionedDescendant()); - break; - } - } -} - -bool RenderLayer::acceleratedCompositingForOverflowScrollEnabled() const -{ - const Settings* settings = renderer()->document().settings(); - return settings && settings->acceleratedCompositingForOverflowScrollEnabled(); -} - -// FIXME: This is a temporary flag and should be removed once accelerated -// overflow scroll is ready (crbug.com/254111). -bool RenderLayer::compositorDrivenAcceleratedScrollingEnabled() const -{ - if (!acceleratedCompositingForOverflowScrollEnabled()) - return false; - - const Settings* settings = renderer()->document().settings(); - return settings && settings->compositorDrivenAcceleratedScrollingEnabled(); -} - bool RenderLayer::scrollsWithRespectTo(const RenderLayer* other) const { const EPosition position = renderer()->style()->position(); @@ -413,21 +366,28 @@ bool RenderLayer::scrollsWithRespectTo(const RenderLayer* other) const const bool isRootFixedPos = position == FixedPosition && containingBlock->enclosingLayer() == rootLayer; const bool otherIsRootFixedPos = otherPosition == FixedPosition && otherContainingBlock->enclosingLayer() == rootLayer; + // FIXME: some of these cases don't look quite right. if (isRootFixedPos && otherIsRootFixedPos) return false; if (isRootFixedPos || otherIsRootFixedPos) return true; - if (containingBlock == otherContainingBlock) + if (containingBlock->enclosingLayer() == otherContainingBlock->enclosingLayer()) return false; // Maintain a set of containing blocks between the first layer and its // closest scrollable ancestor. - HashSet<const RenderObject*> containingBlocks; + HashSet<const RenderLayer*> containingBlocks; while (containingBlock) { + containingBlocks.add(containingBlock->enclosingLayer()); if (containingBlock->enclosingLayer()->scrollsOverflow()) break; - containingBlocks.add(containingBlock); + + if (containingBlock->enclosingLayer() == other) { + // This layer does not scroll with respect to the other layer if the other one does not scroll and this one is a child. + return false; + } + containingBlock = containingBlock->containingBlock(); } @@ -435,7 +395,7 @@ bool RenderLayer::scrollsWithRespectTo(const RenderLayer* other) const // it means both layers are contained within a single non-scrolling subtree. // Hence, they will not scroll with respect to each other. while (otherContainingBlock) { - if (containingBlocks.contains(otherContainingBlock)) + if (containingBlocks.contains(otherContainingBlock->enclosingLayer())) return false; if (otherContainingBlock->enclosingLayer()->scrollsOverflow()) break; @@ -448,24 +408,17 @@ bool RenderLayer::scrollsWithRespectTo(const RenderLayer* other) const void RenderLayer::updateLayerPositionsAfterDocumentScroll() { ASSERT(this == renderer()->view()->layer()); - - RenderGeometryMap geometryMap(UseTransforms); - updateLayerPositionsAfterScroll(&geometryMap); + updateLayerPositionsAfterScroll(); } void RenderLayer::updateLayerPositionsAfterOverflowScroll() { - RenderGeometryMap geometryMap(UseTransforms); - RenderView* view = renderer()->view(); - if (this != view->layer()) - geometryMap.pushMappingsToAncestor(parent(), 0); - // FIXME: why is it OK to not check the ancestors of this layer in order to // initialize the HasSeenViewportConstrainedAncestor and HasSeenAncestorWithOverflowClip flags? - updateLayerPositionsAfterScroll(&geometryMap, IsOverflowScroll); + updateLayerPositionsAfterScroll(IsOverflowScroll); } -void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap, UpdateLayerPositionsAfterScrollFlags flags) +void RenderLayer::updateLayerPositionsAfterScroll(UpdateLayerPositionsAfterScrollFlags flags) { // FIXME: This shouldn't be needed, but there are some corner cases where // these flags are still dirty. Update so that the check below is valid. @@ -477,14 +430,10 @@ void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap if (subtreeIsInvisible()) return; - bool positionChanged = updateLayerPosition(); - if (positionChanged) + if (updateLayerPosition()) flags |= HasChangedAncestor; - if (geometryMap) - geometryMap->pushMappingsToAncestor(this, parent()); - - if (flags & HasChangedAncestor || flags & HasSeenViewportConstrainedAncestor || flags & IsOverflowScroll) + if ((flags & HasChangedAncestor) || (flags & HasSeenViewportConstrainedAncestor) || (flags & IsOverflowScroll)) m_clipper.clearClipRects(); if (renderer()->style()->hasViewportConstrainedPosition()) @@ -493,57 +442,42 @@ void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap if (renderer()->hasOverflowClip()) flags |= HasSeenAncestorWithOverflowClip; - if (flags & HasSeenViewportConstrainedAncestor - || (flags & IsOverflowScroll && flags & HasSeenAncestorWithOverflowClip && !m_canSkipRepaintRectsUpdateOnScroll)) { + if ((flags & IsOverflowScroll) && (flags & HasSeenAncestorWithOverflowClip) && !m_canSkipRepaintRectsUpdateOnScroll) { // FIXME: We could track the repaint container as we walk down the tree. - repainter().computeRepaintRects(renderer()->containerForRepaint(), geometryMap); + repainter().computeRepaintRects(); } else { // Check that RenderLayerRepainter's cached rects are correct. // FIXME: re-enable these assertions when the issue with table cells is resolved: https://bugs.webkit.org/show_bug.cgi?id=103432 - // ASSERT(repainter().m_repaintRect == renderer()->clippedOverflowRectForRepaint(renderer()->containerForRepaint())); - // ASSERT(repainter().m_outlineBox == renderer()->outlineBoundsForRepaint(renderer()->containerForRepaint(), geometryMap)); + // ASSERT(repainter().m_repaintRect == renderer()->clippedOverflowRectForPaintInvalidation(renderer()->containerForPaintInvalidation())); } for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) - child->updateLayerPositionsAfterScroll(geometryMap, flags); + child->updateLayerPositionsAfterScroll(flags); // We don't update our reflection as scrolling is a translation which does not change the size() // of an object, thus RenderReplica will still repaint itself properly as the layer position was // updated above. - - if (geometryMap) - geometryMap->popMappingsToAncestor(parent()); } -bool RenderLayer::hasBlendMode() const +void RenderLayer::updateTransformationMatrix() { - return RuntimeEnabledFeatures::cssCompositingEnabled() && renderer()->hasBlendMode(); + if (m_transform) { + RenderBox* box = renderBox(); + ASSERT(box); + m_transform->makeIdentity(); + box->style()->applyTransform(*m_transform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::IncludeTransformOrigin); + makeMatrixRenderable(*m_transform, compositor()->hasAcceleratedCompositing()); + } } -void RenderLayer::updateBlendMode() +void RenderLayer::updateTransform(const RenderStyle* oldStyle, RenderStyle* newStyle) { - if (!RuntimeEnabledFeatures::cssCompositingEnabled()) + if (oldStyle && newStyle->transformDataEquivalent(*oldStyle)) return; - bool hadBlendMode = m_blendMode != blink::WebBlendModeNormal; - blink::WebBlendMode newBlendMode = renderer()->style()->blendMode(); - if (newBlendMode != m_blendMode) { - m_blendMode = newBlendMode; - - // Only update the flag if a blend mode is set or unset. - if (parent() && (!hadBlendMode || !hasBlendMode())) - parent()->dirtyAncestorChainBlendedDescendantStatus(); - - if (hasCompositedLayerMapping()) - compositedLayerMapping()->setBlendMode(newBlendMode); - } -} - -void RenderLayer::updateTransform() -{ // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set, // so check style too. - bool hasTransform = renderer()->hasTransform() && renderer()->style()->hasTransform(); + bool hasTransform = renderer()->hasTransform() && newStyle->hasTransform(); bool had3DTransform = has3DTransform(); bool hadTransform = m_transform; @@ -555,40 +489,47 @@ void RenderLayer::updateTransform() // Layers with transforms act as clip rects roots, so clear the cached clip rects here. m_clipper.clearClipRectsIncludingDescendants(); + } else if (hasTransform) { + m_clipper.clearClipRectsIncludingDescendants(AbsoluteClipRects); } - if (hasTransform) { - RenderBox* box = renderBox(); - ASSERT(box); - m_transform->makeIdentity(); - box->style()->applyTransform(*m_transform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::IncludeTransformOrigin); - makeMatrixRenderable(*m_transform, canRender3DTransforms()); - } + updateTransformationMatrix(); if (had3DTransform != has3DTransform()) dirty3DTransformedDescendantStatus(); } +static RenderLayer* enclosingLayerForContainingBlock(RenderLayer* layer) +{ + if (RenderObject* containingBlock = layer->renderer()->containingBlock()) + return containingBlock->enclosingLayer(); + return 0; +} + +RenderLayer* RenderLayer::renderingContextRoot() +{ + RenderLayer* renderingContext = 0; + + if (shouldPreserve3D()) + renderingContext = this; + + for (RenderLayer* current = enclosingLayerForContainingBlock(this); current && current->shouldPreserve3D(); current = enclosingLayerForContainingBlock(current)) + renderingContext = current; + + return renderingContext; +} + TransformationMatrix RenderLayer::currentTransform(RenderStyle::ApplyTransformOrigin applyOrigin) const { if (!m_transform) return TransformationMatrix(); - // FIXME: handle this under web-animations - if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled() && renderer()->style()->isRunningAcceleratedAnimation()) { - TransformationMatrix currTransform; - RefPtr<RenderStyle> style = renderer()->animation().getAnimatedStyleForRenderer(renderer()); - style->applyTransform(currTransform, renderBox()->pixelSnappedBorderBoxRect().size(), applyOrigin); - makeMatrixRenderable(currTransform, canRender3DTransforms()); - return currTransform; - } - // m_transform includes transform-origin, so we need to recompute the transform here. if (applyOrigin == RenderStyle::ExcludeTransformOrigin) { RenderBox* box = renderBox(); TransformationMatrix currTransform; box->style()->applyTransform(currTransform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::ExcludeTransformOrigin); - makeMatrixRenderable(currTransform, canRender3DTransforms()); + makeMatrixRenderable(currTransform, compositor()->hasAcceleratedCompositing()); return currTransform; } @@ -609,6 +550,18 @@ TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavio return *m_transform; } +RenderLayer* RenderLayer::enclosingOverflowClipLayer(IncludeSelfOrNot includeSelf) const +{ + const RenderLayer* layer = (includeSelf == IncludeSelf) ? this : parent(); + while (layer) { + if (layer->renderer()->hasOverflowClip()) + return const_cast<RenderLayer*>(layer); + + layer = layer->parent(); + } + return 0; +} + static bool checkContainingBlockChainForPagination(RenderLayerModelObject* renderer, RenderBox* ancestorColumnsRenderer) { RenderView* view = renderer->view(); @@ -633,8 +586,7 @@ static bool checkContainingBlockChainForPagination(RenderLayerModelObject* rende bool RenderLayer::useRegionBasedColumns() const { - const Settings* settings = renderer()->document().settings(); - return settings && settings->regionBasedColumnsEnabled(); + return renderer()->document().regionBasedColumnsEnabled(); } void RenderLayer::updatePagination() @@ -654,7 +606,7 @@ void RenderLayer::updatePagination() // layers). We track an enclosingPaginationLayer instead of using a simple bit, since we want to be able to get back // to that layer easily. bool regionBasedColumnsUsed = useRegionBasedColumns(); - if (regionBasedColumnsUsed && renderer()->isInFlowRenderFlowThread()) { + if (regionBasedColumnsUsed && renderer()->isRenderFlowThread()) { m_enclosingPaginationLayer = this; return; } @@ -694,17 +646,88 @@ void RenderLayer::updatePagination() } // If we're not normal flow, then we need to look for a multi-column object between us and our stacking container. - RenderLayerStackingNode* ancestorStackingContainerNode = m_stackingNode->ancestorStackingContainerNode(); + RenderLayerStackingNode* ancestorStackingContextNode = m_stackingNode->ancestorStackingContextNode(); for (RenderLayer* curr = parent(); curr; curr = curr->parent()) { if (curr->renderer()->hasColumns()) { m_isPaginated = checkContainingBlockChainForPagination(renderer(), curr->renderBox()); return; } - if (curr->stackingNode() == ancestorStackingContainerNode) + if (curr->stackingNode() == ancestorStackingContextNode) return; } } +static RenderLayerModelObject* getTransformedAncestor(const RenderLayerModelObject* repaintContainer) +{ + ASSERT(repaintContainer->layer()->enclosingTransformedAncestor()); + ASSERT(repaintContainer->layer()->enclosingTransformedAncestor()->renderer()); + + // FIXME: this defensive code should not have to exist. None of these pointers should ever be 0. See crbug.com/370410. + RenderLayerModelObject* transformedAncestor = 0; + if (RenderLayer* ancestor = repaintContainer->layer()->enclosingTransformedAncestor()) + transformedAncestor = ancestor->renderer(); + return transformedAncestor; +} + +LayoutPoint RenderLayer::positionFromPaintInvalidationContainer(const RenderObject* renderObject, const RenderLayerModelObject* repaintContainer) +{ + if (!repaintContainer || !repaintContainer->groupedMapping()) + return renderObject->positionFromPaintInvalidationContainer(repaintContainer); + + RenderLayerModelObject* transformedAncestor = getTransformedAncestor(repaintContainer); + if (!transformedAncestor) + return renderObject->positionFromPaintInvalidationContainer(repaintContainer); + + // If the transformedAncestor is actually the RenderView, we might get + // confused and think that we can use LayoutState. Ideally, we'd made + // LayoutState work for all composited layers as well, but until then + // we need to disable LayoutState for squashed layers. + ForceHorriblySlowRectMapping slowRectMapping(*transformedAncestor); + + LayoutPoint point = renderObject->positionFromPaintInvalidationContainer(transformedAncestor); + point.moveBy(-repaintContainer->groupedMapping()->squashingOffsetFromTransformedAncestor()); + return point; +} + +void RenderLayer::mapRectToRepaintBacking(const RenderObject* renderObject, const RenderLayerModelObject* repaintContainer, LayoutRect& rect) +{ + if (!repaintContainer->groupedMapping()) { + renderObject->mapRectToPaintInvalidationBacking(repaintContainer, rect); + return; + } + + RenderLayerModelObject* transformedAncestor = getTransformedAncestor(repaintContainer); + if (!transformedAncestor) + return; + + // If the transformedAncestor is actually the RenderView, we might get + // confused and think that we can use LayoutState. Ideally, we'd made + // LayoutState work for all composited layers as well, but until then + // we need to disable LayoutState for squashed layers. + ForceHorriblySlowRectMapping slowRectMapping(*transformedAncestor); + + // This code adjusts the repaint rectangle to be in the space of the transformed ancestor of the grouped (i.e. squashed) + // layer. This is because all layers that squash together need to repaint w.r.t. a single container that is + // an ancestor of all of them, in order to properly take into account any local transforms etc. + // FIXME: remove this special-case code that works around the repainting code structure. + renderObject->mapRectToPaintInvalidationBacking(repaintContainer, rect); + + // |repaintContainer| may have a local 2D transform on it, so take that into account when mapping into the space of the + // transformed ancestor. + rect = LayoutRect(repaintContainer->localToContainerQuad(FloatRect(rect), transformedAncestor).boundingBox()); + + rect.moveBy(-repaintContainer->groupedMapping()->squashingOffsetFromTransformedAncestor()); +} + +LayoutRect RenderLayer::computeRepaintRect(const RenderObject* renderObject, const RenderLayer* repaintContainer) +{ + if (!repaintContainer->groupedMapping()) + return renderObject->computePaintInvalidationRect(repaintContainer->renderer()); + LayoutRect rect = renderObject->clippedOverflowRectForPaintInvalidation(repaintContainer->renderer()); + mapRectToRepaintBacking(repaintContainer->renderer(), repaintContainer->renderer(), rect); + return rect; +} + void RenderLayer::setHasVisibleContent() { if (m_hasVisibleContent && !m_visibleContentStatusDirty) { @@ -712,19 +735,11 @@ void RenderLayer::setHasVisibleContent() return; } - m_visibleContentStatusDirty = false; m_hasVisibleContent = true; - repainter().computeRepaintRects(renderer()->containerForRepaint()); - if (!m_stackingNode->isNormalFlowOnly()) { - // We don't collect invisible layers in z-order lists if we are not in compositing mode. - // As we became visible, we need to dirty our stacking containers ancestors to be properly - // collected. FIXME: When compositing, we could skip this dirtying phase. - for (RenderLayerStackingNode* sc = m_stackingNode->ancestorStackingContainerNode(); sc; sc = sc->ancestorStackingContainerNode()) { - sc->dirtyZOrderLists(); - if (sc->layer()->hasVisibleContent()) - break; - } - } + m_visibleContentStatusDirty = false; + + setNeedsCompositingInputsUpdate(); + repainter().computeRepaintRects(); if (parent()) parent()->setAncestorChainHasVisibleDescendant(); @@ -758,135 +773,84 @@ void RenderLayer::setAncestorChainHasVisibleDescendant() } } -void RenderLayer::dirtyAncestorChainBlendedDescendantStatus() -{ - for (RenderLayer* layer = this; layer; layer = layer->parent()) { - if (layer->m_childLayerHasBlendModeStatusDirty) - break; - - layer->m_childLayerHasBlendModeStatusDirty = true; - - if (layer->stackingNode()->isStackingContext()) - break; - } -} - -void RenderLayer::setAncestorChainBlendedDescendant() -{ - for (RenderLayer* layer = this; layer; layer = layer->parent()) { - if (!layer->m_childLayerHasBlendModeStatusDirty && layer->childLayerHasBlendMode()) - break; - - layer->m_childLayerHasBlendMode = true; - layer->m_childLayerHasBlendModeStatusDirty = false; - - if (layer->stackingNode()->isStackingContext()) - break; - } -} - -void RenderLayer::updateHasUnclippedDescendant() -{ - TRACE_EVENT0("blink_rendering", "RenderLayer::updateHasUnclippedDescendant"); - ASSERT(renderer()->isOutOfFlowPositioned()); - if (!m_hasVisibleContent && !m_hasVisibleDescendant) - return; - - FrameView* frameView = renderer()->view()->frameView(); - if (!frameView) - return; - - const RenderObject* containingBlock = renderer()->containingBlock(); - setIsUnclippedDescendant(false); - for (RenderLayer* ancestor = parent(); ancestor && ancestor->renderer() != containingBlock; ancestor = ancestor->parent()) { - // TODO(vollick): This isn't quite right. Whenever ancestor is composited and clips - // overflow, we're technically unclipped. However, this will currently cause a huge - // number of layers to report that they are unclipped. Eventually, when we've formally - // separated the clipping, transform, opacity, and stacking trees here and in the - // compositor, we will be able to relax this restriction without it being prohibitively - // expensive (currently, we have to do a lot of work in the compositor to honor a - // clip child/parent relationship). - if (ancestor->scrollsOverflow()) - setIsUnclippedDescendant(true); - ancestor->setHasUnclippedDescendant(true); - } -} - // FIXME: this is quite brute-force. We could be more efficient if we were to -// track state and update it as appropriate as changes are made in the RenderObject tree. -void RenderLayer::updateHasVisibleNonLayerContent() +// track state and update it as appropriate as changes are made in the Render tree. +void RenderLayer::updateScrollingStateAfterCompositingChange() { - TRACE_EVENT0("blink_rendering", "RenderLayer::updateHasVisibleNonLayerContent"); + TRACE_EVENT0("blink_rendering", "RenderLayer::updateScrollingStateAfterCompositingChange"); m_hasVisibleNonLayerContent = false; - for (RenderObject* r = renderer()->firstChild(); r; r = r->nextSibling()) { + for (RenderObject* r = renderer()->slowFirstChild(); r; r = r->nextSibling()) { if (!r->hasLayer()) { m_hasVisibleNonLayerContent = true; break; } } -} -static bool subtreeContainsOutOfFlowPositionedLayer(const RenderLayer* subtreeRoot) -{ - return (subtreeRoot->renderer() && subtreeRoot->renderer()->isOutOfFlowPositioned()) || subtreeRoot->hasOutOfFlowPositionedDescendant(); + m_hasNonCompositedChild = false; + for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { + if (child->compositingState() == NotComposited) { + m_hasNonCompositedChild = true; + return; + } + } } void RenderLayer::updateDescendantDependentFlags() { - if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty || m_hasOutOfFlowPositionedDescendantDirty) { + if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty) { m_hasVisibleDescendant = false; m_hasSelfPaintingLayerDescendant = false; - m_hasOutOfFlowPositionedDescendant = false; for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { child->updateDescendantDependentFlags(); bool hasVisibleDescendant = child->m_hasVisibleContent || child->m_hasVisibleDescendant; bool hasSelfPaintingLayerDescendant = child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant(); - bool hasOutOfFlowPositionedDescendant = subtreeContainsOutOfFlowPositionedLayer(child); m_hasVisibleDescendant |= hasVisibleDescendant; m_hasSelfPaintingLayerDescendant |= hasSelfPaintingLayerDescendant; - m_hasOutOfFlowPositionedDescendant |= hasOutOfFlowPositionedDescendant; - if (m_hasVisibleDescendant && m_hasSelfPaintingLayerDescendant && hasOutOfFlowPositionedDescendant) + if (m_hasVisibleDescendant && m_hasSelfPaintingLayerDescendant) break; } m_visibleDescendantStatusDirty = false; m_hasSelfPaintingLayerDescendantDirty = false; - m_hasOutOfFlowPositionedDescendantDirty = false; } - if (m_childLayerHasBlendModeStatusDirty) { - m_childLayerHasBlendMode = false; + if (m_blendInfo.childLayerHasBlendModeStatusDirty()) { + m_blendInfo.setChildLayerHasBlendMode(false); for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { if (!child->stackingNode()->isStackingContext()) child->updateDescendantDependentFlags(); - bool childLayerHasBlendMode = child->paintsWithBlendMode() || (child->m_childLayerHasBlendMode && !child->stackingNode()->isStackingContext()); - m_childLayerHasBlendMode |= childLayerHasBlendMode; + bool childLayerHadBlendMode = child->blendInfo().childLayerHasBlendModeWhileDirty(); + bool childLayerHasBlendMode = childLayerHadBlendMode || child->blendInfo().hasBlendMode(); - if (m_childLayerHasBlendMode) + m_blendInfo.setChildLayerHasBlendMode(childLayerHasBlendMode); + + if (childLayerHasBlendMode) break; } - m_childLayerHasBlendModeStatusDirty = false; + m_blendInfo.setChildLayerHasBlendModeStatusDirty(false); } if (m_visibleContentStatusDirty) { + bool previouslyHasVisibleContent = m_hasVisibleContent; if (renderer()->style()->visibility() == VISIBLE) m_hasVisibleContent = true; else { // layer may be hidden but still have some visible content, check for this m_hasVisibleContent = false; - RenderObject* r = renderer()->firstChild(); + RenderObject* r = renderer()->slowFirstChild(); while (r) { if (r->style()->visibility() == VISIBLE && !r->hasLayer()) { m_hasVisibleContent = true; break; } - if (r->firstChild() && !r->hasLayer()) - r = r->firstChild(); + RenderObject* rendererFirstChild = r->slowFirstChild(); + if (rendererFirstChild && !r->hasLayer()) + r = rendererFirstChild; else if (r->nextSibling()) r = r->nextSibling(); else { @@ -901,12 +865,17 @@ void RenderLayer::updateDescendantDependentFlags() } } m_visibleContentStatusDirty = false; + + // FIXME: We can remove this code once we remove the recursive tree + // walk inside updateGraphicsLayerGeometry. + if (hasVisibleContent() != previouslyHasVisibleContent) + setNeedsCompositingInputsUpdate(); } } void RenderLayer::dirty3DTransformedDescendantStatus() { - RenderLayerStackingNode* stackingNode = m_stackingNode->ancestorStackingContainerNode(); + RenderLayerStackingNode* stackingNode = m_stackingNode->ancestorStackingContextNode(); if (!stackingNode) return; @@ -916,7 +885,7 @@ void RenderLayer::dirty3DTransformedDescendantStatus() // Note that preserves3D() creates stacking context, so we can just run up the stacking containers. while (stackingNode && stackingNode->layer()->preserves3D()) { stackingNode->layer()->m_3DTransformedDescendantStatusDirty = true; - stackingNode = stackingNode->ancestorStackingContainerNode(); + stackingNode = stackingNode->ancestorStackingContextNode(); } } @@ -949,6 +918,7 @@ bool RenderLayer::updateLayerPosition() { LayoutPoint localPoint; 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()->isInline() && renderer()->isRenderInline()) { RenderInline* inlineFlow = toRenderInline(renderer()); IntRect lineBox = inlineFlow->linesBoundingBox(); @@ -990,20 +960,17 @@ bool RenderLayer::updateLayerPosition() } if (renderer()->isOutOfFlowPositioned() && positionedParent->renderer()->isInFlowPositioned() && positionedParent->renderer()->isRenderInline()) { - LayoutSize offset = toRenderInline(positionedParent->renderer())->offsetForInFlowPositionedInline(toRenderBox(renderer())); + LayoutSize offset = toRenderInline(positionedParent->renderer())->offsetForInFlowPositionedInline(*toRenderBox(renderer())); localPoint += offset; } } else if (parent()) { if (hasCompositedLayerMapping()) { // FIXME: Composited layers ignore pagination, so about the best we can do is make sure they're offset into the appropriate column. // They won't split across columns properly. - LayoutSize columnOffset; - if (!parent()->renderer()->hasColumns() && parent()->renderer()->isRoot() && renderer()->view()->hasColumns()) - renderer()->view()->adjustForColumns(columnOffset, localPoint); + if (!parent()->renderer()->hasColumns() && parent()->renderer()->isDocumentElement() && renderer()->view()->hasColumns()) + localPoint += renderer()->view()->columnOffset(localPoint); else - parent()->renderer()->adjustForColumns(columnOffset, localPoint); - - localPoint += columnOffset; + localPoint += parent()->renderer()->columnOffset(localPoint); } if (parent()->renderer()->hasOverflowClip()) { @@ -1068,8 +1035,7 @@ FloatPoint RenderLayer::perspectiveOrigin() const const LayoutRect borderBox = toRenderBox(renderer())->borderBoxRect(); RenderStyle* style = renderer()->style(); - return FloatPoint(floatValueForLength(style->perspectiveOriginX(), borderBox.width()), - floatValueForLength(style->perspectiveOriginY(), borderBox.height())); + return FloatPoint(floatValueForLength(style->perspectiveOriginX(), borderBox.width().toFloat()), floatValueForLength(style->perspectiveOriginY(), borderBox.height().toFloat())); } static inline bool isFixedPositionedContainer(RenderLayer* layer) @@ -1086,14 +1052,6 @@ RenderLayer* RenderLayer::enclosingPositionedAncestor() const return curr; } -RenderLayer* RenderLayer::enclosingScrollableLayer() const -{ - if (RenderBox* enclosingScrollableBox = renderer()->enclosingScrollableBox()) - return enclosingScrollableBox->layer(); - - return 0; -} - RenderLayer* RenderLayer::enclosingTransformedAncestor() const { RenderLayer* curr = parent(); @@ -1103,9 +1061,29 @@ RenderLayer* RenderLayer::enclosingTransformedAncestor() const return curr; } -static inline const RenderLayer* compositingContainer(const RenderLayer* layer) +LayoutPoint RenderLayer::computeOffsetFromTransformedAncestor() const +{ + const CompositingInputs& properties = compositingInputs(); + + TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint()); + // FIXME: add a test that checks flipped writing mode and ApplyContainerFlip are correct. + renderer()->mapLocalToContainer(properties.transformAncestor ? properties.transformAncestor->renderer() : 0, transformState, ApplyContainerFlip); + transformState.flatten(); + return LayoutPoint(transformState.lastPlanarPoint()); +} + +const RenderLayer* RenderLayer::compositingContainer() const +{ + if (stackingNode()->isNormalFlowOnly()) + return parent(); + if (RenderLayerStackingNode* ancestorStackingNode = stackingNode()->ancestorStackingContextNode()) + return ancestorStackingNode->layer(); + return 0; +} + +bool RenderLayer::isRepaintContainer() const { - return layer->stackingNode()->isNormalFlowOnly() ? layer->parent() : (layer->stackingNode()->ancestorStackingContainerNode() ? layer->stackingNode()->ancestorStackingContainerNode()->layer() : 0); + return compositingState() == PaintsIntoOwnBacking || compositingState() == PaintsIntoGroupedBacking; } // FIXME: having two different functions named enclosingCompositingLayer and enclosingCompositingLayerForRepaint @@ -1113,12 +1091,14 @@ static inline const RenderLayer* compositingContainer(const RenderLayer* layer) // the includeSelf option. It is very likely that we don't even want either of these functions; A layer // should be told explicitly which GraphicsLayer is the repaintContainer for a RenderLayer, and // any other use cases should probably have an API between the non-compositing and compositing sides of code. -RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const +RenderLayer* RenderLayer::enclosingCompositingLayer(IncludeSelfOrNot includeSelf) const { - if (includeSelf && compositingState() != NotComposited && compositingState() != PaintsIntoGroupedBacking) + ASSERT(isAllowedToQueryCompositingState()); + + if ((includeSelf == IncludeSelf) && compositingState() != NotComposited && compositingState() != PaintsIntoGroupedBacking) return const_cast<RenderLayer*>(this); - for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) { + for (const RenderLayer* curr = compositingContainer(); curr; curr = curr->compositingContainer()) { if (curr->compositingState() != NotComposited && curr->compositingState() != PaintsIntoGroupedBacking) return const_cast<RenderLayer*>(curr); } @@ -1126,59 +1106,92 @@ RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const return 0; } -RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(bool includeSelf) const +RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(IncludeSelfOrNot includeSelf) const { - if (includeSelf && (compositingState() == PaintsIntoOwnBacking || compositingState() == PaintsIntoGroupedBacking)) + ASSERT(isAllowedToQueryCompositingState()); + + if ((includeSelf == IncludeSelf) && isRepaintContainer()) return const_cast<RenderLayer*>(this); - for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) { - if (curr->compositingState() == PaintsIntoOwnBacking || curr->compositingState() == PaintsIntoGroupedBacking) + for (const RenderLayer* curr = compositingContainer(); curr; curr = curr->compositingContainer()) { + if (curr->isRepaintContainer()) return const_cast<RenderLayer*>(curr); } return 0; } -RenderLayer* RenderLayer::ancestorCompositedScrollingLayer() const +RenderLayer* RenderLayer::ancestorScrollingLayer() const { - if (!acceleratedCompositingForOverflowScrollEnabled()) - return 0; + for (RenderObject* container = renderer()->containingBlock(); container; container = container->containingBlock()) { + RenderLayer* currentLayer = container->enclosingLayer(); + if (currentLayer->scrollsOverflow()) + return currentLayer; + } - RenderObject* containingBlock = renderer()->containingBlock(); - if (!containingBlock) - return 0; + return 0; +} - for (RenderLayer* ancestorLayer = containingBlock->enclosingLayer(); ancestorLayer; ancestorLayer = ancestorLayer->parent()) { - if (ancestorLayer->needsCompositedScrolling()) - return ancestorLayer; +RenderLayer* RenderLayer::enclosingFilterLayer(IncludeSelfOrNot includeSelf) const +{ + const RenderLayer* curr = (includeSelf == IncludeSelf) ? this : parent(); + for (; curr; curr = curr->parent()) { + if (curr->requiresFullLayerImageForFilters()) + return const_cast<RenderLayer*>(curr); } return 0; } -RenderLayer* RenderLayer::ancestorScrollingLayer() const +void RenderLayer::setNeedsCompositingInputsUpdate() { - RenderObject* containingBlock = renderer()->containingBlock(); - if (!containingBlock) - return 0; + m_needsCompositingInputsUpdate = true; - for (RenderLayer* ancestorLayer = containingBlock->enclosingLayer(); ancestorLayer; ancestorLayer = ancestorLayer->parent()) { - if (ancestorLayer->scrollsOverflow()) - return ancestorLayer; - } + for (RenderLayer* current = this; current && !current->m_childNeedsCompositingInputsUpdate; current = current->parent()) + current->m_childNeedsCompositingInputsUpdate = true; +} - return 0; +void RenderLayer::updateCompositingInputs(const CompositingInputs& compositingInputs) +{ + m_compositingInputs = compositingInputs; + m_needsCompositingInputsUpdate = false; } -RenderLayer* RenderLayer::enclosingFilterLayer(bool includeSelf) const +void RenderLayer::clearChildNeedsCompositingInputsUpdate() { - const RenderLayer* curr = includeSelf ? this : parent(); - for (; curr; curr = curr->parent()) { - if (curr->requiresFullLayerImageForFilters()) - return const_cast<RenderLayer*>(curr); - } + ASSERT(!m_needsCompositingInputsUpdate); + m_childNeedsCompositingInputsUpdate = false; +} - return 0; +void RenderLayer::setCompositingReasons(CompositingReasons reasons, CompositingReasons mask) +{ + ASSERT(reasons == (reasons & mask)); + if ((compositingReasons() & mask) == (reasons & mask)) + return; + m_compositingReasons = (reasons & mask) | (compositingReasons() & ~mask); + m_clipper.setCompositingClipRectsDirty(); +} + +void RenderLayer::setHasCompositingDescendant(bool hasCompositingDescendant) +{ + if (m_hasCompositingDescendant == static_cast<unsigned>(hasCompositingDescendant)) + return; + + m_hasCompositingDescendant = hasCompositingDescendant; + + if (hasCompositedLayerMapping()) + compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateLocal); +} + +void RenderLayer::setShouldIsolateCompositedDescendants(bool shouldIsolateCompositedDescendants) +{ + if (m_shouldIsolateCompositedDescendants == static_cast<unsigned>(shouldIsolateCompositedDescendants)) + return; + + m_shouldIsolateCompositedDescendants = shouldIsolateCompositedDescendants; + + if (hasCompositedLayerMapping()) + compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateLocal); } bool RenderLayer::hasAncestorWithFilterOutsets() const @@ -1191,28 +1204,6 @@ bool RenderLayer::hasAncestorWithFilterOutsets() const return false; } -RenderLayer* RenderLayer::clippingRootForPainting() const -{ - if (hasCompositedLayerMapping()) - return const_cast<RenderLayer*>(this); - - const RenderLayer* current = this; - while (current) { - if (current->isRootLayer()) - return const_cast<RenderLayer*>(current); - - current = compositingContainer(current); - ASSERT(current); - if (current->transform() - || (current->compositingState() == PaintsIntoOwnBacking) - ) - return const_cast<RenderLayer*>(current); - } - - ASSERT_NOT_REACHED(); - return 0; -} - bool RenderLayer::cannotBlitToWindow() const { if (isTransparent() || m_reflectionInfo || hasTransform()) @@ -1222,14 +1213,6 @@ bool RenderLayer::cannotBlitToWindow() const return parent()->cannotBlitToWindow(); } -bool RenderLayer::isTransparent() const -{ - if (renderer()->node() && renderer()->node()->isSVGElement()) - return false; - - return renderer()->isTransparent() || renderer()->hasMask(); -} - RenderLayer* RenderLayer::transparentPaintingAncestor() { if (hasCompositedLayerMapping()) @@ -1254,10 +1237,10 @@ enum TransparencyClipBoxMode { RootOfTransparencyClipBox }; -static LayoutRect transparencyClipBox(const RenderLayer*, const RenderLayer* rootLayer, TransparencyClipBoxBehavior, TransparencyClipBoxMode, PaintBehavior = 0); +static LayoutRect transparencyClipBox(const RenderLayer*, const RenderLayer* rootLayer, TransparencyClipBoxBehavior, TransparencyClipBoxMode, const LayoutSize& subPixelAccumulation, PaintBehavior = 0); static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer* layer, const RenderLayer* rootLayer, - TransparencyClipBoxBehavior transparencyBehavior, PaintBehavior paintBehavior) + TransparencyClipBoxBehavior transparencyBehavior, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior) { // If we have a mask, then the clip is limited to the border box area (and there is // no need to examine child layers). @@ -1266,7 +1249,7 @@ static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, cons // a stacking container. This means we can just walk the layer tree directly. for (RenderLayer* curr = layer->firstChild(); curr; curr = curr->nextSibling()) { if (!layer->reflectionInfo() || layer->reflectionInfo()->reflectionLayer() != curr) - clipRect.unite(transparencyClipBox(curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior)); + clipRect.unite(transparencyClipBox(curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, subPixelAccumulation, paintBehavior)); } } @@ -1284,7 +1267,7 @@ static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, cons } static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior, - TransparencyClipBoxMode transparencyMode, PaintBehavior paintBehavior) + TransparencyClipBoxMode transparencyMode, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior) { // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the // paintDirtyRect, and that should cut down on the amount we have to paint. Still it @@ -1299,14 +1282,16 @@ static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLaye LayoutPoint delta; layer->convertToLayerCoords(rootLayerForTransform, delta); + delta.move(subPixelAccumulation); + IntPoint pixelSnappedDelta = roundedIntPoint(delta); TransformationMatrix transform; - transform.translate(delta.x(), delta.y()); + transform.translate(pixelSnappedDelta.x(), pixelSnappedDelta.y()); transform = transform * *layer->transform(); // We don't use fragment boxes when collecting a transformed layer's bounding box, since it always // paints unfragmented. - LayoutRect clipRect = layer->boundingBox(layer); - expandClipRectForDescendantsAndReflection(clipRect, layer, layer, transparencyBehavior, paintBehavior); + LayoutRect clipRect = layer->physicalBoundingBox(layer); + expandClipRectForDescendantsAndReflection(clipRect, layer, layer, transparencyBehavior, subPixelAccumulation, paintBehavior); layer->renderer()->style()->filterOutsets().expandRect(clipRect); LayoutRect result = transform.mapRect(clipRect); if (!paginationLayer) @@ -1324,36 +1309,41 @@ static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLaye return result; } - LayoutRect clipRect = layer->boundingBox(rootLayer, RenderLayer::UseFragmentBoxes); - expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transparencyBehavior, paintBehavior); + LayoutRect clipRect = layer->physicalBoundingBox(rootLayer); + expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transparencyBehavior, subPixelAccumulation, paintBehavior); layer->renderer()->style()->filterOutsets().expandRect(clipRect); + clipRect.move(subPixelAccumulation); return clipRect; } -LayoutRect RenderLayer::paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior) +LayoutRect RenderLayer::paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior) { - return intersection(transparencyClipBox(this, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintBehavior), paintDirtyRect); + return intersection(transparencyClipBox(this, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, subPixelAccumulation, paintBehavior), paintDirtyRect); } -void RenderLayer::beginTransparencyLayers(GraphicsContext* context, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior) +void RenderLayer::beginTransparencyLayers(GraphicsContext* context, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior) { - bool createTransparencyLayerForBlendMode = m_stackingNode->isStackingContext() && m_childLayerHasBlendMode; + bool createTransparencyLayerForBlendMode = m_stackingNode->isStackingContext() && m_blendInfo.childLayerHasBlendMode(); if (context->paintingDisabled() || ((paintsWithTransparency(paintBehavior) || paintsWithBlendMode() || createTransparencyLayerForBlendMode) && m_usedTransparency)) return; RenderLayer* ancestor = transparentPaintingAncestor(); if (ancestor) - ancestor->beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior); + ancestor->beginTransparencyLayers(context, rootLayer, paintDirtyRect, subPixelAccumulation, paintBehavior); if (paintsWithTransparency(paintBehavior) || paintsWithBlendMode() || createTransparencyLayerForBlendMode) { m_usedTransparency = true; context->save(); - LayoutRect clipRect = paintingExtent(rootLayer, paintDirtyRect, paintBehavior); + LayoutRect clipRect = paintingExtent(rootLayer, paintDirtyRect, subPixelAccumulation, paintBehavior); context->clip(clipRect); + if (paintsWithBlendMode()) - context->setCompositeOperation(context->compositeOperation(), m_blendMode); + context->setCompositeOperation(context->compositeOperation(), m_blendInfo.blendMode()); context->beginTransparencyLayer(renderer()->opacity()); + + if (paintsWithBlendMode()) + context->setCompositeOperation(context->compositeOperation(), blink::WebBlendModeNormal); #ifdef REVEAL_TRANSPARENCY_LAYERS context->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f)); context->fillRect(clipRect); @@ -1388,16 +1378,19 @@ void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild) } else setLastChild(child); - child->setParent(this); + child->m_parent = this; + + setNeedsCompositingInputsUpdate(); + compositor()->setNeedsCompositingUpdate(CompositingUpdateRebuildTree); if (child->stackingNode()->isNormalFlowOnly()) m_stackingNode->dirtyNormalFlowList(); if (!child->stackingNode()->isNormalFlowOnly() || child->firstChild()) { - // Dirty the z-order list in which we are contained. The ancestorStackingContainerNode() can be null in the + // Dirty the z-order list in which we are contained. The ancestorStackingContextNode() can be null in the // case where we're building up generated content layers. This is ok, since the lists will start // off dirty in that case anyway. - child->stackingNode()->dirtyStackingContainerZOrderLists(); + child->stackingNode()->dirtyStackingContextZOrderLists(); } child->updateDescendantDependentFlags(); @@ -1407,32 +1400,12 @@ void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild) if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant()) setAncestorChainHasSelfPaintingLayerDescendant(); - if (child->paintsWithBlendMode() || child->childLayerHasBlendMode()) - setAncestorChainBlendedDescendant(); - - if (subtreeContainsOutOfFlowPositionedLayer(child)) { - // Now that the out of flow positioned descendant is in the tree, we - // need to tell the compositor to reevaluate the compositing - // requirements since we may be able to mark more layers as having - // an 'unclipped' descendant. - compositor()->setNeedsUpdateCompositingRequirementsState(); - setAncestorChainHasOutOfFlowPositionedDescendant(); - } - - // When we first dirty a layer, we will also dirty all the siblings in that - // layer's stacking context. We need to manually do it here as well, in case - // we're adding this layer after the stacking context has already been - // updated. - child->stackingNode()->setDescendantsAreContiguousInStackingOrderDirty(true); - compositor()->layerWasAdded(this, child); + if (child->blendInfo().hasBlendMode() || child->blendInfo().childLayerHasBlendMode()) + m_blendInfo.setAncestorChainBlendedDescendant(); } RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild) { - if (!renderer()->documentBeingDestroyed()) - compositor()->layerWillBeRemoved(this, oldChild); - - // remove the child if (oldChild->previousSibling()) oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); if (oldChild->nextSibling()) @@ -1448,28 +1421,25 @@ RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild) if (!oldChild->stackingNode()->isNormalFlowOnly() || oldChild->firstChild()) { // Dirty the z-order list in which we are contained. When called via the // reattachment process in removeOnlyThisLayer, the layer may already be disconnected - // from the main layer tree, so we need to null-check the |stackingContainer| value. - oldChild->stackingNode()->dirtyStackingContainerZOrderLists(); + // from the main layer tree, so we need to null-check the + // |stackingContext| value. + oldChild->stackingNode()->dirtyStackingContextZOrderLists(); } + if (renderer()->style()->visibility() != VISIBLE) + dirtyVisibleContentStatus(); + oldChild->setPreviousSibling(0); oldChild->setNextSibling(0); - oldChild->setParent(0); + oldChild->m_parent = 0; oldChild->updateDescendantDependentFlags(); - if (subtreeContainsOutOfFlowPositionedLayer(oldChild)) { - // It may now be the case that a layer no longer has an unclipped - // descendant. Let the compositor know that it needs to reevaluate - // its compositing requirements to check this. - compositor()->setNeedsUpdateCompositingRequirementsState(); - dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus(); - } if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant) dirtyAncestorChainVisibleDescendantStatus(); - if (oldChild->paintsWithBlendMode() || oldChild->childLayerHasBlendMode()) - dirtyAncestorChainBlendedDescendantStatus(); + if (oldChild->m_blendInfo.hasBlendMode() || oldChild->blendInfo().childLayerHasBlendMode()) + m_blendInfo.dirtyAncestorChainBlendedDescendantStatus(); if (oldChild->isSelfPaintingLayer() || oldChild->hasSelfPaintingLayerDescendant()) dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); @@ -1482,9 +1452,6 @@ void RenderLayer::removeOnlyThisLayer() if (!m_parent) return; - compositor()->layerWillBeRemoved(m_parent, this); - - // Dirty the clip rects. m_clipper.clearClipRectsIncludingDescendants(); RenderLayer* nextSib = nextSibling(); @@ -1500,8 +1467,16 @@ void RenderLayer::removeOnlyThisLayer() RenderLayer* next = current->nextSibling(); removeChild(current); m_parent->addChild(current, nextSib); - current->repainter().setRepaintStatus(NeedsFullRepaint); - current->updateLayerPositions(0); // FIXME: use geometry map. + + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + current->renderer()->setShouldDoFullPaintInvalidationAfterLayout(true); + else + current->repainter().setRepaintStatus(NeedsFullRepaint); + + // Hits in compositing/overflow/automatically-opt-into-composited-scrolling-part-1.html + DisableCompositingQueryAsserts disabler; + + current->updateLayerPositionRecursive(); current = next; } @@ -1522,27 +1497,13 @@ void RenderLayer::insertOnlyThisLayer() } // Remove all descendant layers from the hierarchy and add them to the new position. - for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling()) + for (RenderObject* curr = renderer()->slowFirstChild(); curr; curr = curr->nextSibling()) curr->moveLayers(m_parent, this); // Clear out all the clip rects. m_clipper.clearClipRectsIncludingDescendants(); } -void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& roundedLocation) const -{ - LayoutPoint location = roundedLocation; - convertToLayerCoords(ancestorLayer, location); - roundedLocation = roundedIntPoint(location); -} - -void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntRect& roundedRect) const -{ - LayoutRect rect = roundedRect; - convertToLayerCoords(ancestorLayer, rect); - roundedRect = pixelSnappedIntRect(rect); -} - // Returns the layer reached on the walk up towards the ancestor. static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutPoint& location) { @@ -1559,7 +1520,7 @@ static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay // FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in a RenderFlowThread // may need to be revisited in a future patch. // If the fixed renderer is inside a RenderFlowThread, we should not compute location using localToAbsolute, - // since localToAbsolute maps the coordinates from named flow to regions coordinates and regions can be + // since localToAbsolute maps the coordinates from flow thread to regions coordinates and regions can be // positioned in a completely different place in the viewport (RenderView). if (position == FixedPosition && !fixedFlowThreadContainer && (!ancestorLayer || ancestorLayer == renderer->view()->layer())) { // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling @@ -1627,8 +1588,7 @@ static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay // We should not reach RenderView layer past the RenderFlowThread layer for any // children of the RenderFlowThread. - if (renderer->flowThreadContainingBlock() && !layer->isOutOfFlowRenderFlowThread()) - ASSERT(parentLayer != renderer->view()->layer()); + ASSERT(!renderer->flowThreadContainingBlock() || parentLayer != renderer->view()->layer()); if (foundAncestorFirst) { // Found ancestorLayer before the abs. positioned container, so compute offset of both relative @@ -1673,8 +1633,7 @@ void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutR RenderLayer* RenderLayer::scrollParent() const { - if (!compositorDrivenAcceleratedScrollingEnabled()) - return 0; + ASSERT(compositor()->acceleratedCompositingForOverflowScrollEnabled()); // Normal flow elements will be parented under the main scrolling layer, so // we don't need a scroll parent/child relationship to get them to scroll. @@ -1693,16 +1652,18 @@ RenderLayer* RenderLayer::scrollParent() const // our scrolling ancestor, and we will therefore not scroll with it. In this case, we must // be a composited layer since the compositor will need to take special measures to ensure // that we scroll with our scrolling ancestor and it cannot do this if we do not promote. - RenderLayer* scrollParent = ancestorCompositedScrollingLayer(); - if (!scrollParent || scrollParent->stackingNode()->isStackingContainer()) + RenderLayer* scrollParent = ancestorScrollingLayer(); + if (!scrollParent || scrollParent->stackingNode()->isStackingContext()) return 0; // If we hit a stacking context on our way up to the ancestor scrolling layer, it will already // be composited due to an overflow scrolling parent, so we don't need to. for (RenderLayer* ancestor = parent(); ancestor && ancestor != scrollParent; ancestor = ancestor->parent()) { - if (ancestor->stackingNode()->isStackingContainer()) - return 0; + if (ancestor->stackingNode()->isStackingContext()) { + scrollParent = 0; + break; + } } return scrollParent; @@ -1710,38 +1671,24 @@ RenderLayer* RenderLayer::scrollParent() const RenderLayer* RenderLayer::clipParent() const { - const bool needsAncestorClip = compositor()->clippedByAncestor(this); - - RenderLayer* clipParent = 0; - if ((compositingReasons() & CompositingReasonOutOfFlowClipping) && !needsAncestorClip) { + if (compositingReasons() & CompositingReasonOutOfFlowClipping && !compositor()->clippedByNonAncestorInStackingTree(this)) { if (RenderObject* containingBlock = renderer()->containingBlock()) - clipParent = containingBlock->enclosingLayer()->enclosingCompositingLayer(true); + return containingBlock->enclosingLayer()->enclosingCompositingLayer(); } - - return clipParent; + return 0; } void RenderLayer::didUpdateNeedsCompositedScrolling() { - m_stackingNode->updateIsNormalFlowOnly(); updateSelfPaintingLayer(); - - if (m_stackingNode->isStackingContainer()) - m_stackingNode->dirtyZOrderLists(); - else - m_stackingNode->clearZOrderLists(); - - m_stackingNode->dirtyStackingContainerZOrderLists(); - - compositor()->setNeedsToRecomputeCompositingRequirements(); - compositor()->setCompositingLayersNeedRebuild(); } void RenderLayer::updateReflectionInfo(const RenderStyle* oldStyle) { + ASSERT(!oldStyle || !renderer()->style()->reflectionDataEquivalent(oldStyle)); if (renderer()->hasReflection()) { if (!m_reflectionInfo) - m_reflectionInfo = adoptPtr(new RenderLayerReflectionInfo(toRenderBox(renderer()))); + m_reflectionInfo = adoptPtr(new RenderLayerReflectionInfo(*renderBox())); m_reflectionInfo->updateAfterStyleChange(oldStyle); } else if (m_reflectionInfo) { m_reflectionInfo = nullptr; @@ -1759,7 +1706,7 @@ void RenderLayer::updateStackingNode() void RenderLayer::updateScrollableArea() { if (requiresScrollableArea()) - m_scrollableArea = adoptPtr(new RenderLayerScrollableArea(renderBox())); + m_scrollableArea = adoptPtr(new RenderLayerScrollableArea(*this)); else m_scrollableArea = nullptr; } @@ -1776,12 +1723,13 @@ bool RenderLayer::hasOverflowControls() const return m_scrollableArea && (m_scrollableArea->hasScrollbar() || m_scrollableArea->hasScrollCorner() || renderer()->style()->resize() != RESIZE_NONE); } -void RenderLayer::paint(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot, RenderRegion* region, PaintLayerFlags paintFlags) +void RenderLayer::paint(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot, PaintLayerFlags paintFlags) { OverlapTestRequestMap overlapTestRequests; - LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), paintingRoot, region, &overlapTestRequests); - paintLayer(context, paintingInfo, paintFlags); + LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), paintingRoot, &overlapTestRequests); + if (shouldPaintLayerInSoftwareMode(context, paintingInfo, paintFlags)) + paintLayer(context, paintingInfo, paintFlags); OverlapTestRequestMap::iterator end = overlapTestRequests.end(); for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) @@ -1813,10 +1761,10 @@ static bool inContainingBlockChain(RenderLayer* startLayer, RenderLayer* endLaye return false; } -void RenderLayer::clipToRect(RenderLayer* rootLayer, GraphicsContext* context, const LayoutRect& paintDirtyRect, const ClipRect& clipRect, - BorderRadiusClippingRule rule) +void RenderLayer::clipToRect(const LayerPaintingInfo& localPaintingInfo, GraphicsContext* context, const ClipRect& clipRect, + PaintLayerFlags paintFlags, BorderRadiusClippingRule rule) { - if (clipRect.rect() == paintDirtyRect && !clipRect.hasRadius()) + if (clipRect.rect() == localPaintingInfo.paintDirtyRect && !clipRect.hasRadius()) return; context->save(); context->clip(pixelSnappedIntRect(clipRect.rect())); @@ -1828,13 +1776,20 @@ void RenderLayer::clipToRect(RenderLayer* rootLayer, GraphicsContext* context, c // any layers with overflow. The condition for being able to apply these clips is that the overflow object be in our // containing block chain so we check that also. for (RenderLayer* layer = rule == IncludeSelfForBorderRadius ? this : parent(); layer; layer = layer->parent()) { + // Composited scrolling layers handle border-radius clip in the compositor via a mask layer. We do not + // want to apply a border-radius clip to the layer contents itself, because that would require re-rastering + // every frame to update the clip. We only want to make sure that the mask layer is properly clipped so + // that it can in turn clip the scrolled contents in the compositor. + if (layer->needsCompositedScrolling() && !(paintFlags & PaintLayerPaintingChildClippingMaskPhase)) + break; + if (layer->renderer()->hasOverflowClip() && layer->renderer()->style()->hasBorderRadius() && inContainingBlockChain(this, layer)) { LayoutPoint delta; - layer->convertToLayerCoords(rootLayer, delta); + layer->convertToLayerCoords(localPaintingInfo.rootLayer, delta); context->clipRoundedRect(layer->renderer()->style()->getRoundedInnerBorderFor(LayoutRect(delta, layer->size()))); } - if (layer == rootLayer) + if (layer == localPaintingInfo.rootLayer) break; } } @@ -1850,7 +1805,7 @@ static void performOverlapTests(OverlapTestRequestMap& overlapTestRequests, cons { Vector<RenderWidget*> overlappedRequestClients; OverlapTestRequestMap::iterator end = overlapTestRequests.end(); - LayoutRect boundingBox = layer->boundingBox(rootLayer); + LayoutRect boundingBox = layer->physicalBoundingBox(rootLayer); for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) { if (!boundingBox.intersects(it->value)) continue; @@ -1858,13 +1813,7 @@ static void performOverlapTests(OverlapTestRequestMap& overlapTestRequests, cons it->key->setIsOverlapped(true); overlappedRequestClients.append(it->key); } - for (size_t i = 0; i < overlappedRequestClients.size(); ++i) - overlapTestRequests.remove(overlappedRequestClients[i]); -} - -static bool shouldDoSoftwarePaint(const RenderLayer* layer, bool paintingReflection) -{ - return paintingReflection && !layer->has3DTransform(); + overlapTestRequests.removeAll(overlappedRequestClients); } static inline bool shouldSuppressPaintingLayer(RenderLayer* layer) @@ -1872,7 +1821,7 @@ static inline bool shouldSuppressPaintingLayer(RenderLayer* layer) // Avoid painting descendants of the root layer when stylesheets haven't loaded. This eliminates FOUC. // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document // will do a full repaint(). - if (layer->renderer()->document().didLayoutWithPendingStylesheets() && !layer->isRootLayer() && !layer->renderer()->isRoot()) + if (layer->renderer()->document().didLayoutWithPendingStylesheets() && !layer->isRootLayer() && !layer->renderer()->isDocumentElement()) return true; return false; @@ -1880,21 +1829,22 @@ static inline bool shouldSuppressPaintingLayer(RenderLayer* layer) static bool paintForFixedRootBackground(const RenderLayer* layer, PaintLayerFlags paintFlags) { - return layer->renderer()->isRoot() && (paintFlags & PaintLayerPaintingRootBackgroundOnly); + return layer->renderer()->isDocumentElement() && (paintFlags & PaintLayerPaintingRootBackgroundOnly); +} + +static ShouldRespectOverflowClip shouldRespectOverflowClip(PaintLayerFlags paintFlags, const RenderObject* renderer) +{ + return (paintFlags & PaintLayerPaintingOverflowContents || (paintFlags & PaintLayerPaintingChildClippingMaskPhase && renderer->hasClipPath())) ? IgnoreOverflowClip : RespectOverflowClip; } void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) { - if (compositingState() != NotComposited && compositingState() != PaintsIntoGroupedBacking) { - // The updatingControlTints() painting pass goes through compositing layers, - // but we need to ensure that we don't cache clip rects computed with the wrong root in this case. + // https://code.google.com/p/chromium/issues/detail?id=343772 + DisableCompositingQueryAsserts disabler; + + if (compositingState() != NotComposited) { if (context->updatingControlTints() || (paintingInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers)) { paintFlags |= PaintLayerTemporaryClipRects; - } else if (!compositedLayerMapping()->paintsIntoCompositedAncestor() - && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection) - && !paintForFixedRootBackground(this, paintFlags)) { - // If this RenderLayer should paint into its own backing, that will be done via CompositedLayerMapping::paintIntoLayer(). - return; } } else if (viewportConstrainedNotCompositedReason() == NotCompositedForBoundsOutOfView) { // Don't paint out-of-view viewport constrained layers (when doing prepainting) because they will never be visible @@ -1927,9 +1877,9 @@ void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo& // layer from the parent now, assuming there is a parent if (paintFlags & PaintLayerHaveTransparency) { if (parent()) - parent()->beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.paintBehavior); + parent()->beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior); else - beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.paintBehavior); + beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior); } if (enclosingPaginationLayer()) { @@ -1940,13 +1890,13 @@ void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo& // Make sure the parent's clip rects have been calculated. ClipRect clipRect = paintingInfo.paintDirtyRect; if (parent()) { - ClipRectsContext clipRectsContext(paintingInfo.rootLayer, paintingInfo.region, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, - IgnoreOverlayScrollbarSize, (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip); - clipRect = backgroundClipRect(clipRectsContext); + ClipRectsContext clipRectsContext(paintingInfo.rootLayer, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, + IgnoreOverlayScrollbarSize, shouldRespectOverflowClip(paintFlags, renderer())); + clipRect = clipper().backgroundClipRect(clipRectsContext); clipRect.intersect(paintingInfo.paintDirtyRect); // Push the parent coordinate space's clip. - parent()->clipToRect(paintingInfo.rootLayer, context, paintingInfo.paintDirtyRect, clipRect); + parent()->clipToRect(paintingInfo, context, clipRect, paintFlags); } paintLayerByApplyingTransform(context, paintingInfo, paintFlags); @@ -2003,7 +1953,7 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti GraphicsContext* transparencyLayerContext = context; - if (paintFlags & PaintLayerPaintingRootBackgroundOnly && !renderer()->isRenderView() && !renderer()->isRoot()) + if (paintFlags & PaintLayerPaintingRootBackgroundOnly && !renderer()->isRenderView() && !renderer()->isDocumentElement()) return; // Ensure our lists are up-to-date. @@ -2012,7 +1962,10 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti LayoutPoint offsetFromRoot; convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot); - IntRect rootRelativeBounds; + if (compositingState() == PaintsIntoOwnBacking) + offsetFromRoot.move(subpixelAccumulation()); + + LayoutRect rootRelativeBounds; bool rootRelativeBoundsComputed = false; // Apply clip-path to context. @@ -2020,7 +1973,11 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti RenderStyle* style = renderer()->style(); RenderSVGResourceClipper* resourceClipper = 0; ClipperContext clipperContext; - if (renderer()->hasClipPath() && !context->paintingDisabled() && style) { + + // Clip-path, like border radius, must not be applied to the contents of a composited-scrolling container. + // It must, however, still be applied to the mask layer, so that the compositor can properly mask the + // scrolling contents and scrollbars. + if (renderer()->hasClipPath() && !context->paintingDisabled() && style && (!needsCompositedScrolling() || paintFlags & PaintLayerPaintingChildClippingMaskPhase)) { ASSERT(style->clipPath()); if (style->clipPath()->type() == ClipPathOperation::SHAPE) { hasClipPath = true; @@ -2028,7 +1985,7 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti ShapeClipPathOperation* clipPath = toShapeClipPathOperation(style->clipPath()); if (!rootRelativeBoundsComputed) { - rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0); + rootRelativeBounds = physicalBoundingBoxIncludingReflectionAndStackingChildren(paintingInfo.rootLayer, offsetFromRoot); rootRelativeBoundsComputed = true; } @@ -2038,9 +1995,9 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti Document& document = renderer()->document(); // FIXME: It doesn't work with forward or external SVG references (https://bugs.webkit.org/show_bug.cgi?id=90405) Element* element = document.getElementById(referenceClipPathOperation->fragment()); - if (element && element->hasTagName(SVGNames::clipPathTag) && element->renderer()) { + if (isSVGClipPathElement(element) && element->renderer()) { if (!rootRelativeBoundsComputed) { - rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0); + rootRelativeBounds = physicalBoundingBoxIncludingReflectionAndStackingChildren(paintingInfo.rootLayer, offsetFromRoot); rootRelativeBoundsComputed = true; } @@ -2056,10 +2013,10 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti // Blending operations must be performed only with the nearest ancestor stacking context. // Note that there is no need to create a transparency layer if we're painting the root. - bool createTransparencyLayerForBlendMode = !renderer()->isRoot() && m_stackingNode->isStackingContext() && m_childLayerHasBlendMode; + bool createTransparencyLayerForBlendMode = !renderer()->isDocumentElement() && m_stackingNode->isStackingContext() && m_blendInfo.childLayerHasBlendMode(); if (createTransparencyLayerForBlendMode) - beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.paintBehavior); + beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior); LayerPaintingInfo localPaintingInfo(paintingInfo); FilterEffectRendererHelper filterPainter(filterRenderer() && paintsWithFilters()); @@ -2069,10 +2026,8 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti LayoutRect filterRepaintRect = filterInfo->dirtySourceRect(); filterRepaintRect.move(offsetFromRoot.x(), offsetFromRoot.y()); - if (!rootRelativeBoundsComputed) { - rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0); - rootRelativeBoundsComputed = true; - } + if (!rootRelativeBoundsComputed) + rootRelativeBounds = physicalBoundingBoxIncludingReflectionAndStackingChildren(paintingInfo.rootLayer, offsetFromRoot); if (filterPainter.prepareFilterEffect(this, rootRelativeBounds, paintingInfo.paintDirtyRect, filterRepaintRect)) { // Now we know for sure, that the source image will be updated, so we can revert our tracking repaint rect back to zero. @@ -2097,7 +2052,7 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti if (filterPainter.hasStartedFilterEffect() && haveTransparency) { // If we have a filter and transparency, we have to eagerly start a transparency layer here, rather than risk a child layer lazily starts one with the wrong context. - beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, paintingInfo.paintDirtyRect, localPaintingInfo.paintBehavior); + beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, localPaintingInfo.paintBehavior); } // If this layer's renderer is a child of the paintingRoot, we render unconditionally, which @@ -2132,37 +2087,39 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) { // Collect the fragments. This will compute the clip rectangles and paint offsets for each layer fragment, as well as whether or not the content of each // fragment should paint. - collectFragments(layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.region, localPaintingInfo.paintDirtyRect, + collectFragments(layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize, - (isPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, &offsetFromRoot); + shouldRespectOverflowClip(paintFlags, renderer()), &offsetFromRoot, localPaintingInfo.subPixelAccumulation); updatePaintingInfoForFragments(layerFragments, localPaintingInfo, paintFlags, shouldPaintContent, &offsetFromRoot); } - if (shouldPaintBackground) + if (shouldPaintBackground) { paintBackgroundForFragments(layerFragments, context, transparencyLayerContext, paintingInfo.paintDirtyRect, haveTransparency, - localPaintingInfo, paintBehavior, paintingRootForRenderer); + localPaintingInfo, paintBehavior, paintingRootForRenderer, paintFlags); + } if (shouldPaintNegZOrderList) paintChildren(NegativeZOrderChildren, context, localPaintingInfo, paintFlags); - if (shouldPaintOwnContents) + if (shouldPaintOwnContents) { paintForegroundForFragments(layerFragments, context, transparencyLayerContext, paintingInfo.paintDirtyRect, haveTransparency, - localPaintingInfo, paintBehavior, paintingRootForRenderer, selectionOnly, forceBlackText); + localPaintingInfo, paintBehavior, paintingRootForRenderer, selectionOnly, forceBlackText, paintFlags); + } if (shouldPaintOutline) - paintOutlineForFragments(layerFragments, context, localPaintingInfo, paintBehavior, paintingRootForRenderer); + paintOutlineForFragments(layerFragments, context, localPaintingInfo, paintBehavior, paintingRootForRenderer, paintFlags); if (shouldPaintNormalFlowAndPosZOrderLists) paintChildren(NormalFlowChildren | PositiveZOrderChildren, context, localPaintingInfo, paintFlags); if (shouldPaintOverlayScrollbars) - paintOverflowControlsForFragments(layerFragments, context, localPaintingInfo); + paintOverflowControlsForFragments(layerFragments, context, localPaintingInfo, paintFlags); if (filterPainter.hasStartedFilterEffect()) { // Apply the correct clipping (ie. overflow: hidden). // FIXME: It is incorrect to just clip to the damageRect here once multiple fragments are involved. ClipRect backgroundRect = layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect; - clipToRect(localPaintingInfo.rootLayer, transparencyLayerContext, localPaintingInfo.paintDirtyRect, backgroundRect); + clipToRect(localPaintingInfo, transparencyLayerContext, backgroundRect, paintFlags); context = filterPainter.applyFilterEffect(); restoreClip(transparencyLayerContext, localPaintingInfo.paintDirtyRect, backgroundRect); } @@ -2171,11 +2128,11 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti ASSERT(transparencyLayerContext == context); if (shouldPaintMask) - paintMaskForFragments(layerFragments, context, localPaintingInfo, paintingRootForRenderer); + paintMaskForFragments(layerFragments, context, localPaintingInfo, paintingRootForRenderer, paintFlags); if (shouldPaintClippingMask) { // Paint the border radius mask for the fragments. - paintChildClippingMaskForFragments(layerFragments, context, localPaintingInfo, paintingRootForRenderer); + paintChildClippingMaskForFragments(layerFragments, context, localPaintingInfo, paintingRootForRenderer, paintFlags); } // End our transparency layer @@ -2205,30 +2162,45 @@ void RenderLayer::paintLayerByApplyingTransform(GraphicsContext* context, const LayoutSize adjustedSubPixelAccumulation = paintingInfo.subPixelAccumulation + (delta - roundedDelta); // Apply the transform. - GraphicsContextStateSaver stateSaver(*context); - context->concatCTM(transform.toAffineTransform()); + GraphicsContextStateSaver stateSaver(*context, false); + if (!transform.isIdentity()) { + stateSaver.save(); + context->concatCTM(transform.toAffineTransform()); + } // Now do a paint with the root layer shifted to be us. LayerPaintingInfo transformedPaintingInfo(this, enclosingIntRect(transform.inverse().mapRect(paintingInfo.paintDirtyRect)), paintingInfo.paintBehavior, - adjustedSubPixelAccumulation, paintingInfo.paintingRoot, paintingInfo.region, paintingInfo.overlapTestRequests); + adjustedSubPixelAccumulation, paintingInfo.paintingRoot, paintingInfo.overlapTestRequests); paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags); } +bool RenderLayer::shouldPaintLayerInSoftwareMode(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) +{ + DisableCompositingQueryAsserts disabler; + + return compositingState() == NotComposited + || compositingState() == HasOwnBackingButPaintsIntoAncestor + || context->updatingControlTints() + || (paintingInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers) + || ((paintFlags & PaintLayerPaintingReflection) && !has3DTransform()) + || paintForFixedRootBackground(this, paintFlags); +} + void RenderLayer::paintChildren(unsigned childrenToVisit, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) { if (!hasSelfPaintingLayerDescendant()) return; -#if !ASSERT_DISABLED +#if ASSERT_ENABLED LayerListMutationDetector mutationChecker(m_stackingNode.get()); #endif RenderLayerStackingNodeIterator iterator(*m_stackingNode, childrenToVisit); while (RenderLayerStackingNode* child = iterator.next()) { RenderLayer* childLayer = child->layer(); - - // Squashed RenderLayers should not paint into their ancestor. - if (childLayer->compositingState() == PaintsIntoGroupedBacking) + // If this RenderLayer should paint into its own backing or a grouped backing, that will be done via CompositedLayerMapping::paintContents() + // and CompositedLayerMapping::doPaintTask(). + if (!childLayer->shouldPaintLayerInSoftwareMode(context, paintingInfo, paintFlags)) continue; if (!childLayer->isPaginated()) @@ -2238,15 +2210,15 @@ void RenderLayer::paintChildren(unsigned childrenToVisit, GraphicsContext* conte } } -void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer* rootLayer, RenderRegion* region, const LayoutRect& dirtyRect, +void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer* rootLayer, const LayoutRect& dirtyRect, ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy, ShouldRespectOverflowClip respectOverflowClip, const LayoutPoint* offsetFromRoot, - const LayoutRect* layerBoundingBox) + const LayoutSize& subPixelAccumulation, const LayoutRect* layerBoundingBox) { if (!enclosingPaginationLayer() || hasTransform()) { // For unpaginated layers, there is only one fragment. LayerFragment fragment; - ClipRectsContext clipRectsContext(rootLayer, region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip); - calculateRects(clipRectsContext, dirtyRect, fragment.layerBounds, fragment.backgroundRect, fragment.foregroundRect, fragment.outlineRect, offsetFromRoot); + ClipRectsContext clipRectsContext(rootLayer, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip, subPixelAccumulation); + clipper().calculateRects(clipRectsContext, dirtyRect, fragment.layerBounds, fragment.backgroundRect, fragment.foregroundRect, fragment.outlineRect, offsetFromRoot); fragments.append(fragment); return; } @@ -2257,16 +2229,16 @@ void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer* // Calculate clip rects relative to the enclosingPaginationLayer. The purpose of this call is to determine our bounds clipped to intermediate // layers between us and the pagination context. It's important to minimize the number of fragments we need to create and this helps with that. - ClipRectsContext paginationClipRectsContext(enclosingPaginationLayer(), region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip); + ClipRectsContext paginationClipRectsContext(enclosingPaginationLayer(), clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip); LayoutRect layerBoundsInFlowThread; ClipRect backgroundRectInFlowThread; ClipRect foregroundRectInFlowThread; ClipRect outlineRectInFlowThread; - calculateRects(paginationClipRectsContext, PaintInfo::infiniteRect(), layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread, + clipper().calculateRects(paginationClipRectsContext, PaintInfo::infiniteRect(), layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread, outlineRectInFlowThread, &offsetWithinPaginatedLayer); // Take our bounding box within the flow thread and clip it. - LayoutRect layerBoundingBoxInFlowThread = layerBoundingBox ? *layerBoundingBox : boundingBox(enclosingPaginationLayer(), 0, &offsetWithinPaginatedLayer); + LayoutRect layerBoundingBoxInFlowThread = layerBoundingBox ? *layerBoundingBox : physicalBoundingBox(enclosingPaginationLayer(), &offsetWithinPaginatedLayer); layerBoundingBoxInFlowThread.intersect(backgroundRectInFlowThread.rect()); // Shift the dirty rect into flow thread coordinates. @@ -2286,8 +2258,8 @@ void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer* // Get the parent clip rects of the pagination layer, since we need to intersect with that when painting column contents. ClipRect ancestorClipRect = dirtyRect; if (enclosingPaginationLayer()->parent()) { - ClipRectsContext clipRectsContext(rootLayer, region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip); - ancestorClipRect = enclosingPaginationLayer()->backgroundClipRect(clipRectsContext); + ClipRectsContext clipRectsContext(rootLayer, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip); + ancestorClipRect = enclosingPaginationLayer()->clipper().backgroundClipRect(clipRectsContext); ancestorClipRect.intersect(dirtyRect); } @@ -2328,10 +2300,10 @@ void RenderLayer::paintTransformedLayerIntoFragments(GraphicsContext* context, c { LayerFragments enclosingPaginationFragments; LayoutPoint offsetOfPaginationLayerFromRoot; - LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintingInfo.paintBehavior); - enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, paintingInfo.rootLayer, paintingInfo.region, paintingInfo.paintDirtyRect, + LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior); + enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize, - (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, &offsetOfPaginationLayerFromRoot, &transformedExtent); + shouldRespectOverflowClip(paintFlags, renderer()), &offsetOfPaginationLayerFromRoot, paintingInfo.subPixelAccumulation, &transformedExtent); for (size_t i = 0; i < enclosingPaginationFragments.size(); ++i) { const LayerFragment& fragment = enclosingPaginationFragments.at(i); @@ -2344,22 +2316,31 @@ void RenderLayer::paintTransformedLayerIntoFragments(GraphicsContext* context, c if (parent() != enclosingPaginationLayer()) { enclosingPaginationLayer()->convertToLayerCoords(paintingInfo.rootLayer, offsetOfPaginationLayerFromRoot); - ClipRectsContext clipRectsContext(enclosingPaginationLayer(), paintingInfo.region, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, - IgnoreOverlayScrollbarSize, (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip); - LayoutRect parentClipRect = backgroundClipRect(clipRectsContext).rect(); + ClipRectsContext clipRectsContext(enclosingPaginationLayer(), (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, + IgnoreOverlayScrollbarSize, shouldRespectOverflowClip(paintFlags, renderer())); + LayoutRect parentClipRect = clipper().backgroundClipRect(clipRectsContext).rect(); parentClipRect.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot); clipRect.intersect(parentClipRect); } - parent()->clipToRect(paintingInfo.rootLayer, context, paintingInfo.paintDirtyRect, clipRect); + parent()->clipToRect(paintingInfo, context, clipRect, paintFlags); paintLayerByApplyingTransform(context, paintingInfo, paintFlags, fragment.paginationOffset); parent()->restoreClip(context, paintingInfo.paintDirtyRect, clipRect); } } +static inline LayoutSize subPixelAccumulationIfNeeded(const LayoutSize& subPixelAccumulation, CompositingState compositingState) +{ + // Only apply the sub-pixel accumulation if we don't paint into our own backing layer, otherwise the position + // of the renderer already includes any sub-pixel offset. + if (compositingState == PaintsIntoOwnBacking) + return LayoutSize(); + return subPixelAccumulation; +} + void RenderLayer::paintBackgroundForFragments(const LayerFragments& layerFragments, GraphicsContext* context, GraphicsContext* transparencyLayerContext, const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior, - RenderObject* paintingRootForRenderer) + RenderObject* paintingRootForRenderer, PaintLayerFlags paintFlags) { for (size_t i = 0; i < layerFragments.size(); ++i) { const LayerFragment& fragment = layerFragments.at(i); @@ -2368,18 +2349,18 @@ void RenderLayer::paintBackgroundForFragments(const LayerFragments& layerFragmen // Begin transparency layers lazily now that we know we have to paint something. if (haveTransparency || paintsWithBlendMode()) - beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.paintBehavior); + beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.subPixelAccumulation, localPaintingInfo.paintBehavior); if (localPaintingInfo.clipToDirtyRect) { // Paint our background first, before painting any child layers. // Establish the clip used to paint our background. - clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self. + clipToRect(localPaintingInfo, context, fragment.backgroundRect, paintFlags, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self. } // Paint the background. // FIXME: Eventually we will collect the region from the fragment itself instead of just from the paint info. - PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseBlockBackground, paintBehavior, paintingRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer()); - renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation)); + PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseBlockBackground, paintBehavior, paintingRootForRenderer, 0, 0, localPaintingInfo.rootLayer->renderer()); + renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState()))); if (localPaintingInfo.clipToDirtyRect) restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect); @@ -2388,14 +2369,14 @@ void RenderLayer::paintBackgroundForFragments(const LayerFragments& layerFragmen void RenderLayer::paintForegroundForFragments(const LayerFragments& layerFragments, GraphicsContext* context, GraphicsContext* transparencyLayerContext, const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior, - RenderObject* paintingRootForRenderer, bool selectionOnly, bool forceBlackText) + RenderObject* paintingRootForRenderer, bool selectionOnly, bool forceBlackText, PaintLayerFlags paintFlags) { // Begin transparency if we have something to paint. if (haveTransparency || paintsWithBlendMode()) { for (size_t i = 0; i < layerFragments.size(); ++i) { const LayerFragment& fragment = layerFragments.at(i); if (fragment.shouldPaintContent && !fragment.foregroundRect.isEmpty()) { - beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.paintBehavior); + beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.subPixelAccumulation, localPaintingInfo.paintBehavior); break; } } @@ -2406,17 +2387,17 @@ void RenderLayer::paintForegroundForFragments(const LayerFragments& layerFragmen // Optimize clipping for the single fragment case. bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() == 1 && layerFragments[0].shouldPaintContent && !layerFragments[0].foregroundRect.isEmpty(); if (shouldClip) - clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, layerFragments[0].foregroundRect); + clipToRect(localPaintingInfo, context, layerFragments[0].foregroundRect, paintFlags); // We have to loop through every fragment multiple times, since we have to repaint in each specific phase in order for // interleaving of the fragments to work properly. paintForegroundForFragmentsWithPhase(selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds, layerFragments, - context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer); + context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer, paintFlags); if (!selectionOnly) { - paintForegroundForFragmentsWithPhase(PaintPhaseFloat, layerFragments, context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer); - paintForegroundForFragmentsWithPhase(PaintPhaseForeground, layerFragments, context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer); - paintForegroundForFragmentsWithPhase(PaintPhaseChildOutlines, layerFragments, context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer); + paintForegroundForFragmentsWithPhase(PaintPhaseFloat, layerFragments, context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer, paintFlags); + paintForegroundForFragmentsWithPhase(PaintPhaseForeground, layerFragments, context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer, paintFlags); + paintForegroundForFragmentsWithPhase(PaintPhaseChildOutlines, layerFragments, context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer, paintFlags); } if (shouldClip) @@ -2424,7 +2405,7 @@ void RenderLayer::paintForegroundForFragments(const LayerFragments& layerFragmen } void RenderLayer::paintForegroundForFragmentsWithPhase(PaintPhase phase, const LayerFragments& layerFragments, GraphicsContext* context, - const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior, RenderObject* paintingRootForRenderer) + const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior, RenderObject* paintingRootForRenderer, PaintLayerFlags paintFlags) { bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() > 1; @@ -2434,12 +2415,12 @@ void RenderLayer::paintForegroundForFragmentsWithPhase(PaintPhase phase, const L continue; if (shouldClip) - clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.foregroundRect); + clipToRect(localPaintingInfo, context, fragment.foregroundRect, paintFlags); - PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.foregroundRect.rect()), phase, paintBehavior, paintingRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer()); + PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.foregroundRect.rect()), phase, paintBehavior, paintingRootForRenderer, 0, 0, localPaintingInfo.rootLayer->renderer()); if (phase == PaintPhaseForeground) paintInfo.overlapTestRequests = localPaintingInfo.overlapTestRequests; - renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation)); + renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState()))); if (shouldClip) restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.foregroundRect); @@ -2447,7 +2428,7 @@ void RenderLayer::paintForegroundForFragmentsWithPhase(PaintPhase phase, const L } void RenderLayer::paintOutlineForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo, - PaintBehavior paintBehavior, RenderObject* paintingRootForRenderer) + PaintBehavior paintBehavior, RenderObject* paintingRootForRenderer, PaintLayerFlags paintFlags) { for (size_t i = 0; i < layerFragments.size(); ++i) { const LayerFragment& fragment = layerFragments.at(i); @@ -2455,15 +2436,15 @@ void RenderLayer::paintOutlineForFragments(const LayerFragments& layerFragments, continue; // Paint our own outline - PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.outlineRect.rect()), PaintPhaseSelfOutline, paintBehavior, paintingRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer()); - clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.outlineRect, DoNotIncludeSelfForBorderRadius); - renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation)); + PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.outlineRect.rect()), PaintPhaseSelfOutline, paintBehavior, paintingRootForRenderer, 0, 0, localPaintingInfo.rootLayer->renderer()); + clipToRect(localPaintingInfo, context, fragment.outlineRect, paintFlags, DoNotIncludeSelfForBorderRadius); + renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState()))); restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.outlineRect); } } void RenderLayer::paintMaskForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo, - RenderObject* paintingRootForRenderer) + RenderObject* paintingRootForRenderer, PaintLayerFlags paintFlags) { for (size_t i = 0; i < layerFragments.size(); ++i) { const LayerFragment& fragment = layerFragments.at(i); @@ -2471,12 +2452,12 @@ void RenderLayer::paintMaskForFragments(const LayerFragments& layerFragments, Gr continue; if (localPaintingInfo.clipToDirtyRect) - clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self. + clipToRect(localPaintingInfo, context, fragment.backgroundRect, paintFlags, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self. // Paint the mask. // FIXME: Eventually we will collect the region from the fragment itself instead of just from the paint info. - PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseMask, PaintBehaviorNormal, paintingRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer()); - renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation)); + PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseMask, PaintBehaviorNormal, paintingRootForRenderer, 0, 0, localPaintingInfo.rootLayer->renderer()); + renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState()))); if (localPaintingInfo.clipToDirtyRect) restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect); @@ -2484,7 +2465,7 @@ void RenderLayer::paintMaskForFragments(const LayerFragments& layerFragments, Gr } void RenderLayer::paintChildClippingMaskForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo, - RenderObject* paintingRootForRenderer) + RenderObject* paintingRootForRenderer, PaintLayerFlags paintFlags) { for (size_t i = 0; i < layerFragments.size(); ++i) { const LayerFragment& fragment = layerFragments.at(i); @@ -2492,24 +2473,24 @@ void RenderLayer::paintChildClippingMaskForFragments(const LayerFragments& layer continue; if (localPaintingInfo.clipToDirtyRect) - clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.foregroundRect, IncludeSelfForBorderRadius); // Child clipping mask painting will handle clipping to self. + clipToRect(localPaintingInfo, context, fragment.foregroundRect, paintFlags, IncludeSelfForBorderRadius); // Child clipping mask painting will handle clipping to self. // Paint the the clipped mask. - PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseClippingMask, PaintBehaviorNormal, paintingRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer()); - renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation)); + PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseClippingMask, PaintBehaviorNormal, paintingRootForRenderer, 0, 0, localPaintingInfo.rootLayer->renderer()); + renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState()))); if (localPaintingInfo.clipToDirtyRect) restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.foregroundRect); } } -void RenderLayer::paintOverflowControlsForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo) +void RenderLayer::paintOverflowControlsForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo, PaintLayerFlags paintFlags) { for (size_t i = 0; i < layerFragments.size(); ++i) { const LayerFragment& fragment = layerFragments.at(i); - clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect); + clipToRect(localPaintingInfo, context, fragment.backgroundRect, paintFlags); if (RenderLayerScrollableArea* scrollableArea = this->scrollableArea()) - scrollableArea->paintOverflowControls(context, roundedIntPoint(toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation)), pixelSnappedIntRect(fragment.backgroundRect.rect()), true); + scrollableArea->paintOverflowControls(context, roundedIntPoint(toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState()))), pixelSnappedIntRect(fragment.backgroundRect.rect()), true); restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect); } } @@ -2518,7 +2499,7 @@ void RenderLayer::paintPaginatedChildLayer(RenderLayer* childLayer, GraphicsCont { // We need to do multiple passes, breaking up our child layer into strips. Vector<RenderLayer*> columnLayers; - RenderLayerStackingNode* ancestorNode = m_stackingNode->isNormalFlowOnly() ? parent()->stackingNode() : m_stackingNode->ancestorStackingContainerNode(); + RenderLayerStackingNode* ancestorNode = m_stackingNode->isNormalFlowOnly() ? parent()->stackingNode() : m_stackingNode->ancestorStackingContextNode(); for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) { if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox())) columnLayers.append(curr); @@ -2527,8 +2508,8 @@ void RenderLayer::paintPaginatedChildLayer(RenderLayer* childLayer, GraphicsCont } // It is possible for paintLayer() to be called after the child layer ceases to be paginated but before - // updateLayerPositions() is called and resets the isPaginated() flag, see <rdar://problem/10098679>. - // If this is the case, just bail out, since the upcoming call to updateLayerPositions() will repaint the layer. + // updateLayerPositionRecursive() is called and resets the isPaginated() flag, see <rdar://problem/10098679>. + // If this is the case, just bail out, since the upcoming call to updateLayerPositionRecursive() will repaint the layer. if (!columnLayers.size()) return; @@ -2582,7 +2563,7 @@ void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, GraphicsCo // Each strip pushes a clip, since column boxes are specified as being // like overflow:hidden. - context->clip(pixelSnappedIntRect(colRect)); + context->clip(enclosingIntRect(colRect)); if (!colIndex) { // Apply a translation transform to change where the layer paints. @@ -2651,9 +2632,9 @@ bool RenderLayer::hitTest(const HitTestRequest& request, const HitTestLocation& // RenderView should make sure to update layout before entering hit testing ASSERT(!renderer()->frame()->view()->layoutPending()); - ASSERT(!renderer()->document().renderer()->needsLayout()); + ASSERT(!renderer()->document().renderView()->needsLayout()); - LayoutRect hitTestArea = isOutOfFlowRenderFlowThread() ? toRenderFlowThread(renderer())->borderBoxRect() : renderer()->view()->documentRect(); + LayoutRect hitTestArea = renderer()->view()->documentRect(); if (!request.ignoreClipping()) hitTestArea.intersect(frameVisibleRect(renderer())); @@ -2694,15 +2675,6 @@ bool RenderLayer::isInTopLayer() const return node && node->isElementNode() && toElement(node)->isInTopLayer(); } -bool RenderLayer::isInTopLayerSubtree() const -{ - for (const RenderLayer* layer = this; layer; layer = layer->parent()) { - if (layer->isInTopLayer()) - return true; - } - return false; -} - // Compute the z-offset of the point in the transformState. // This is effectively projecting a ray normal to the plane of ancestor, finding where that // ray intersects target, and computing the z delta between those two points. @@ -2800,8 +2772,8 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont // Make sure the parent's clip rects have been calculated. if (parent()) { - ClipRectsContext clipRectsContext(rootLayer, hitTestLocation.region(), RootRelativeClipRects, IncludeOverlayScrollbarSize); - ClipRect clipRect = backgroundClipRect(clipRectsContext); + ClipRectsContext clipRectsContext(rootLayer, RootRelativeClipRects, IncludeOverlayScrollbarSize); + ClipRect clipRect = clipper().backgroundClipRect(clipRectsContext); // Go ahead and test the enclosing clip now. if (!clipRect.intersects(hitTestLocation)) return 0; @@ -2886,7 +2858,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont // Collect the fragments. This will compute the clip rectangles for each layer fragment. LayerFragments layerFragments; - collectFragments(layerFragments, rootLayer, hitTestLocation.region(), hitTestRect, RootRelativeClipRects, IncludeOverlayScrollbarSize); + collectFragments(layerFragments, rootLayer, hitTestRect, RootRelativeClipRects, IncludeOverlayScrollbarSize); if (m_scrollableArea && m_scrollableArea->hitTestResizerInFragments(layerFragments, hitTestLocation)) { renderer()->updateHitTestResult(result, hitTestLocation.point()); @@ -2968,9 +2940,10 @@ RenderLayer* RenderLayer::hitTestTransformedLayerInFragments(RenderLayer* rootLa { LayerFragments enclosingPaginationFragments; LayoutPoint offsetOfPaginationLayerFromRoot; - LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), HitTestingTransparencyClipBox, RootOfTransparencyClipBox); - enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, rootLayer, hitTestLocation.region(), hitTestRect, - RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip, &offsetOfPaginationLayerFromRoot, &transformedExtent); + // FIXME: We're missing a sub-pixel offset here crbug.com/348728 + LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), HitTestingTransparencyClipBox, RootOfTransparencyClipBox, LayoutSize()); + enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, rootLayer, hitTestRect, + RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip, &offsetOfPaginationLayerFromRoot, LayoutSize(), &transformedExtent); for (int i = enclosingPaginationFragments.size() - 1; i >= 0; --i) { const LayerFragment& fragment = enclosingPaginationFragments.at(i); @@ -2983,8 +2956,8 @@ RenderLayer* RenderLayer::hitTestTransformedLayerInFragments(RenderLayer* rootLa if (parent() != enclosingPaginationLayer()) { enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOfPaginationLayerFromRoot); - ClipRectsContext clipRectsContext(enclosingPaginationLayer(), hitTestLocation.region(), RootRelativeClipRects, IncludeOverlayScrollbarSize); - LayoutRect parentClipRect = backgroundClipRect(clipRectsContext).rect(); + ClipRectsContext clipRectsContext(enclosingPaginationLayer(), RootRelativeClipRects, IncludeOverlayScrollbarSize); + LayoutRect parentClipRect = clipper().backgroundClipRect(clipRectsContext).rect(); parentClipRect.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot); clipRect.intersect(parentClipRect); } @@ -3100,7 +3073,7 @@ RenderLayer* RenderLayer::hitTestPaginatedChildLayer(RenderLayer* childLayer, Re const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset) { Vector<RenderLayer*> columnLayers; - RenderLayerStackingNode* ancestorNode = m_stackingNode->isNormalFlowOnly() ? parent()->stackingNode() : m_stackingNode->ancestorStackingContainerNode(); + RenderLayerStackingNode* ancestorNode = m_stackingNode->isNormalFlowOnly() ? parent()->stackingNode() : m_stackingNode->ancestorStackingContextNode(); for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) { if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox())) columnLayers.append(curr); @@ -3216,166 +3189,16 @@ RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend return 0; } -void RenderLayer::parentClipRects(const ClipRectsContext& clipRectsContext, ClipRects& clipRects) const -{ - ASSERT(parent()); - if (clipRectsContext.clipRectsType == TemporaryClipRects) { - parent()->clipper().calculateClipRects(clipRectsContext, clipRects); - return; - } - - parent()->m_clipper.updateClipRects(clipRectsContext); - clipRects = *parent()->clipper().clipRects(clipRectsContext); -} - -static inline ClipRect backgroundClipRectForPosition(const ClipRects& parentRects, EPosition position) +void RenderLayer::blockSelectionGapsBoundsChanged() { - if (position == FixedPosition) - return parentRects.fixedClipRect(); - - if (position == AbsolutePosition) - return parentRects.posClipRect(); - - return parentRects.overflowClipRect(); -} - -ClipRect RenderLayer::backgroundClipRect(const ClipRectsContext& clipRectsContext) const -{ - ASSERT(parent()); - - ClipRects parentRects; - - // If we cross into a different pagination context, then we can't rely on the cache. - // Just switch over to using TemporaryClipRects. - if (clipRectsContext.clipRectsType != TemporaryClipRects && parent()->enclosingPaginationLayer() != enclosingPaginationLayer()) { - ClipRectsContext tempContext(clipRectsContext); - tempContext.clipRectsType = TemporaryClipRects; - parentClipRects(tempContext, parentRects); - } else - parentClipRects(clipRectsContext, parentRects); - - ClipRect backgroundClipRect = backgroundClipRectForPosition(parentRects, renderer()->style()->position()); - RenderView* view = renderer()->view(); - ASSERT(view); - - // Note: infinite clipRects should not be scrolled here, otherwise they will accidentally no longer be considered infinite. - if (parentRects.fixed() && clipRectsContext.rootLayer->renderer() == view && backgroundClipRect != PaintInfo::infiniteRect()) - backgroundClipRect.move(view->frameView()->scrollOffsetForFixedPosition()); - - return backgroundClipRect; -} - -void RenderLayer::calculateRects(const ClipRectsContext& clipRectsContext, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, - ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, const LayoutPoint* offsetFromRoot) const -{ - if (clipRectsContext.rootLayer != this && parent()) { - backgroundRect = backgroundClipRect(clipRectsContext); - backgroundRect.intersect(paintDirtyRect); - } else - backgroundRect = paintDirtyRect; - - foregroundRect = backgroundRect; - outlineRect = backgroundRect; - - LayoutPoint offset; - if (offsetFromRoot) - offset = *offsetFromRoot; - else - convertToLayerCoords(clipRectsContext.rootLayer, offset); - layerBounds = LayoutRect(offset, size()); - - // Update the clip rects that will be passed to child layers. - if (renderer()->hasOverflowClip()) { - // This layer establishes a clip of some kind. - if (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip) { - foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(offset, clipRectsContext.region, clipRectsContext.overlayScrollbarSizeRelevancy)); - if (renderer()->style()->hasBorderRadius()) - foregroundRect.setHasRadius(true); - } - - // If we establish an overflow clip at all, then go ahead and make sure our background - // rect is intersected with our layer's bounds including our visual overflow, - // since any visual overflow like box-shadow or border-outset is not clipped by overflow:auto/hidden. - if (renderBox()->hasVisualOverflow()) { - // FIXME: Perhaps we should be propagating the borderbox as the clip rect for children, even though - // we may need to inflate our clip specifically for shadows or outsets. - // FIXME: Does not do the right thing with CSS regions yet, since we don't yet factor in the - // individual region boxes as overflow. - LayoutRect layerBoundsWithVisualOverflow = renderBox()->visualOverflowRect(); - renderBox()->flipForWritingMode(layerBoundsWithVisualOverflow); // Layers are in physical coordinates, so the overflow has to be flipped. - layerBoundsWithVisualOverflow.moveBy(offset); - if (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip) - backgroundRect.intersect(layerBoundsWithVisualOverflow); - } else { - // Shift the bounds to be for our region only. - LayoutRect bounds = renderBox()->borderBoxRectInRegion(clipRectsContext.region); - bounds.moveBy(offset); - if (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip) - backgroundRect.intersect(bounds); - } - } - - // CSS clip (different than clipping due to overflow) can clip to any box, even if it falls outside of the border box. - if (renderer()->hasClip()) { - // Clip applies to *us* as well, so go ahead and update the damageRect. - LayoutRect newPosClip = toRenderBox(renderer())->clipRect(offset, clipRectsContext.region); - backgroundRect.intersect(newPosClip); - foregroundRect.intersect(newPosClip); - outlineRect.intersect(newPosClip); - } -} - -LayoutRect RenderLayer::childrenClipRect() const -{ - // FIXME: border-radius not accounted for. - // FIXME: Regions not accounted for. - RenderView* renderView = renderer()->view(); - RenderLayer* clippingRootLayer = clippingRootForPainting(); - LayoutRect layerBounds; - ClipRect backgroundRect, foregroundRect, outlineRect; - ClipRectsContext clipRectsContext(clippingRootLayer, 0, TemporaryClipRects); - // Need to use temporary clip rects, because the value of 'dontClipToOverflow' may be different from the painting path (<rdar://problem/11844909>). - calculateRects(clipRectsContext, renderView->unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); - return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregroundRect.rect())).enclosingBoundingBox(); -} - -LayoutRect RenderLayer::selfClipRect() const -{ - // FIXME: border-radius not accounted for. - // FIXME: Regions not accounted for. - RenderView* renderView = renderer()->view(); - RenderLayer* clippingRootLayer = clippingRootForPainting(); - LayoutRect layerBounds; - ClipRect backgroundRect, foregroundRect, outlineRect; - ClipRectsContext clipRectsContext(clippingRootLayer, 0, PaintingClipRects); - calculateRects(clipRectsContext, renderView->documentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); - 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 = clippingRootForPainting(); - LayoutRect layerBounds; - ClipRect backgroundRect, foregroundRect, outlineRect; - ClipRectsContext clipRectsContext(clippingRootLayer, 0, PaintingClipRects); - calculateRects(clipRectsContext, 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; + setNeedsCompositingInputsUpdate(); + compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange); } void RenderLayer::addBlockSelectionGapsBounds(const LayoutRect& bounds) { m_blockSelectionGapsBounds.unite(enclosingIntRect(bounds)); + blockSelectionGapsBoundsChanged(); } void RenderLayer::clearBlockSelectionGapsBounds() @@ -3383,6 +3206,7 @@ void RenderLayer::clearBlockSelectionGapsBounds() m_blockSelectionGapsBounds = IntRect(); for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) child->clearBlockSelectionGapsBounds(); + blockSelectionGapsBoundsChanged(); } void RenderLayer::repaintBlockSelectionGaps() @@ -3398,25 +3222,43 @@ void RenderLayer::repaintBlockSelectionGaps() RenderBox* box = renderBox(); rect.move(-box->scrolledContentOffset()); if (!scrollableArea()->usesCompositedScrolling()) - rect.intersect(box->overflowClipRect(LayoutPoint(), 0)); // FIXME: Regions not accounted for. + rect.intersect(box->overflowClipRect(LayoutPoint())); } if (renderer()->hasClip()) - rect.intersect(toRenderBox(renderer())->clipRect(LayoutPoint(), 0)); // FIXME: Regions not accounted for. + rect.intersect(toRenderBox(renderer())->clipRect(LayoutPoint())); if (!rect.isEmpty()) - renderer()->repaintRectangle(rect); + renderer()->invalidatePaintRectangle(rect); +} + +IntRect RenderLayer::blockSelectionGapsBounds() const +{ + if (!renderer()->isRenderBlock()) + return IntRect(); + + RenderBlock* renderBlock = toRenderBlock(renderer()); + LayoutRect gapRects = renderBlock->selectionGapRectsForRepaint(renderBlock); + + return pixelSnappedIntRect(gapRects); } bool RenderLayer::hasBlockSelectionGapBounds() const { - return !m_blockSelectionGapsBounds.isEmpty(); + // FIXME: it would be more accurate to return !blockSelectionGapsBounds().isEmpty(), but this is impossible + // at the moment because it causes invalid queries to layout-dependent code (crbug.com/372802). + // ASSERT(renderer()->document().lifecycle().state() >= DocumentLifecycle::LayoutClean); + + if (!renderer()->isRenderBlock()) + return false; + + return toRenderBlock(renderer())->shouldPaintSelectionGaps(); } bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot) const { // Always examine the canvas and the root. - // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView + // FIXME: Could eliminate the isDocumentElement() check if we fix background painting so that the RenderView // paints the root's background. - if (isRootLayer() || renderer()->isRoot()) + if (isRootLayer() || renderer()->isDocumentElement()) return true; // If we aren't an inline flow, and our layer bounds do intersect the damage rect, then we @@ -3424,18 +3266,16 @@ bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const Layo RenderView* view = renderer()->view(); ASSERT(view); if (view && !renderer()->isRenderInline()) { - LayoutRect b = layerBounds; - b.inflate(view->maximalOutlineSize()); - if (b.intersects(damageRect)) + if (layerBounds.intersects(damageRect)) return true; } // Otherwise we need to compute the bounding box of this single layer and see if it intersects // the damage rect. - return boundingBox(rootLayer, 0, offsetFromRoot).intersects(damageRect); + return physicalBoundingBox(rootLayer, offsetFromRoot).intersects(damageRect); } -LayoutRect RenderLayer::localBoundingBox(CalculateLayerBoundsFlags flags) const +LayoutRect RenderLayer::logicalBoundingBox() const { // There are three special cases we need to consider. // (1) Inline Flows. For inline flows we will create a bounding box that fully encompasses all of the lines occupied by the @@ -3447,11 +3287,11 @@ LayoutRect RenderLayer::localBoundingBox(CalculateLayerBoundsFlags flags) const // as part of our bounding box. We do this because we are the responsible layer for both hit testing and painting those // floats. LayoutRect result; - if (renderer()->isInline() && renderer()->isRenderInline()) + if (renderer()->isInline() && renderer()->isRenderInline()) { result = toRenderInline(renderer())->linesVisualOverflowBoundingBox(); - else if (renderer()->isTableRow()) { + } else if (renderer()->isTableRow()) { // Our bounding box is just the union of all of our cells' border/overflow rects. - for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) { + for (RenderObject* child = renderer()->slowFirstChild(); child; child = child->nextSibling()) { if (child->isTableCell()) { LayoutRect bbox = toRenderBox(child)->borderBoxRect(); result.unite(bbox); @@ -3463,52 +3303,21 @@ LayoutRect RenderLayer::localBoundingBox(CalculateLayerBoundsFlags flags) const } else { RenderBox* box = renderBox(); ASSERT(box); - if (!(flags & DontConstrainForMask) && box->hasMask()) { - result = box->maskClipRect(); - box->flipForWritingMode(result); // The mask clip rect is in physical coordinates, so we have to flip, since localBoundingBox is not. - } else { - LayoutRect bbox = box->borderBoxRect(); - result = bbox; - LayoutRect overflowRect = box->visualOverflowRect(); - if (bbox != overflowRect) - result.unite(overflowRect); - } + result = box->borderBoxRect(); + result.unite(box->visualOverflowRect()); } - RenderView* view = renderer()->view(); - ASSERT(view); - if (view) - result.inflate(view->maximalOutlineSize()); // Used to apply a fudge factor to dirty-rect checks on blocks/tables. - + ASSERT(renderer()->view()); return result; } -LayoutRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer, CalculateLayerBoundsFlags flags, const LayoutPoint* offsetFromRoot) const +LayoutRect RenderLayer::physicalBoundingBox(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot) const { - LayoutRect result = localBoundingBox(flags); - if (renderer()->isBox()) + LayoutRect result = logicalBoundingBox(); + if (m_renderer->isBox()) renderBox()->flipForWritingMode(result); else - renderer()->containingBlock()->flipForWritingMode(result); - - if (enclosingPaginationLayer() && (flags & UseFragmentBoxes)) { - // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to - // get our true bounding box. - LayoutPoint offsetWithinPaginationLayer; - convertToLayerCoords(enclosingPaginationLayer(), offsetWithinPaginationLayer); - result.moveBy(offsetWithinPaginationLayer); - - RenderFlowThread* enclosingFlowThread = toRenderFlowThread(enclosingPaginationLayer()->renderer()); - result = enclosingFlowThread->fragmentsBoundingBox(result); - - LayoutPoint delta; - if (offsetFromRoot) - delta = *offsetFromRoot; - else - enclosingPaginationLayer()->convertToLayerCoords(ancestorLayer, delta); - result.moveBy(delta); - return result; - } + m_renderer->containingBlock()->flipForWritingMode(result); LayoutPoint delta; if (offsetFromRoot) @@ -3520,125 +3329,120 @@ LayoutRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer, CalculateL return result; } -IntRect RenderLayer::absoluteBoundingBox() const +LayoutRect RenderLayer::physicalBoundingBoxIncludingReflectionAndStackingChildren(const RenderLayer* ancestorLayer, const LayoutPoint& offsetFromRoot) const { - return pixelSnappedIntRect(boundingBox(root())); -} + LayoutPoint origin; + LayoutRect result = physicalBoundingBox(ancestorLayer, &origin); -IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot, CalculateLayerBoundsFlags flags) const -{ - if (!isSelfPaintingLayer()) - return IntRect(); + if (m_reflectionInfo && !m_reflectionInfo->reflectionLayer()->hasCompositedLayerMapping()) + result.unite(m_reflectionInfo->reflectionLayer()->physicalBoundingBox(this)); - // FIXME: This could be improved to do a check like hasVisibleNonCompositingDescendantLayers() (bug 92580). - if ((flags & ExcludeHiddenDescendants) && this != ancestorLayer && !hasVisibleContent() && !hasVisibleDescendant()) - return IntRect(); + ASSERT(m_stackingNode->isStackingContext() || !m_stackingNode->hasPositiveZOrderList()); - RenderLayerModelObject* renderer = this->renderer(); + const_cast<RenderLayer*>(this)->stackingNode()->updateLayerListsIfNeeded(); - if (isRootLayer()) { - // The root layer is always just the size of the document. - return renderer->view()->unscaledDocumentRect(); +#if ASSERT_ENABLED + LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(this)->stackingNode()); +#endif + + RenderLayerStackingNodeIterator iterator(*m_stackingNode.get(), AllChildren); + while (RenderLayerStackingNode* node = iterator.next()) { + if (node->layer()->hasCompositedLayerMapping()) + continue; + // FIXME: Can we call physicalBoundingBoxIncludingReflectionAndStackingChildren instead of boundingBoxForCompositing? + result.unite(node->layer()->boundingBoxForCompositing(this)); } - LayoutRect boundingBoxRect = localBoundingBox(flags); + result.moveBy(offsetFromRoot); + return result; +} - if (renderer->isBox()) - toRenderBox(renderer)->flipForWritingMode(boundingBoxRect); - else - renderer->containingBlock()->flipForWritingMode(boundingBoxRect); - - if (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 = 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())); - } +static void expandCompositingRectForStackingChildren(const RenderLayer* ancestorLayer, RenderLayer::CalculateBoundsOptions options, LayoutRect& result) +{ + RenderLayerStackingNodeIterator iterator(*ancestorLayer->stackingNode(), AllChildren); + while (RenderLayerStackingNode* node = iterator.next()) { + // Here we exclude both directly composited layers and squashing layers + // because those RenderLayers don't paint into the graphics layer + // for this RenderLayer. For example, the bounds of squashed RenderLayers + // will be included in the computation of the appropriate squashing + // GraphicsLayer. + if (options != RenderLayer::ApplyBoundsChickenEggHacks && node->layer()->compositingState() != NotComposited) + continue; + result.unite(node->layer()->boundingBoxForCompositing(ancestorLayer, options)); } +} - LayoutRect unionBounds = boundingBoxRect; - bool shouldIncludeTransform = paintsWithTransform(PaintBehaviorNormal) || (transform() && flags & PretendLayerHasOwnBacking); +LayoutRect RenderLayer::boundingBoxForCompositing(const RenderLayer* ancestorLayer, CalculateBoundsOptions options) const +{ + if (!isSelfPaintingLayer()) + return LayoutRect(); - if (flags & UseLocalClipRectIfPossible) { - LayoutRect localClipRect = this->localClipRect(); - if (localClipRect != PaintInfo::infiniteRect()) { - if ((flags & IncludeSelfTransform) && shouldIncludeTransform) - localClipRect = transform()->mapRect(localClipRect); + if (!ancestorLayer) + ancestorLayer = this; - LayoutPoint ancestorRelOffset; - convertToLayerCoords(ancestorLayer, ancestorRelOffset); - localClipRect.moveBy(ancestorRelOffset); - return pixelSnappedIntRect(localClipRect); - } + // FIXME: This could be improved to do a check like hasVisibleNonCompositingDescendantLayers() (bug 92580). + if (this != ancestorLayer && !hasVisibleContent() && !hasVisibleDescendant()) + return LayoutRect(); + + // The root layer is always just the size of the document. + if (isRootLayer()) + return m_renderer->view()->unscaledDocumentRect(); + + const bool shouldIncludeTransform = paintsWithTransform(PaintBehaviorNormal) || (options == ApplyBoundsChickenEggHacks && transform()); + + LayoutRect localClipRect = clipper().localClipRect(); + if (localClipRect != PaintInfo::infiniteRect()) { + if (shouldIncludeTransform) + localClipRect = transform()->mapRect(localClipRect); + + LayoutPoint delta; + convertToLayerCoords(ancestorLayer, delta); + localClipRect.moveBy(delta); + return localClipRect; } - // FIXME: should probably just pass 'flags' down to descendants. - CalculateLayerBoundsFlags descendantFlags = DefaultCalculateLayerBoundsFlags | (flags & ExcludeHiddenDescendants) | (flags & IncludeCompositedDescendants); + LayoutPoint origin; + LayoutRect result = physicalBoundingBox(ancestorLayer, &origin); const_cast<RenderLayer*>(this)->stackingNode()->updateLayerListsIfNeeded(); - if (m_reflectionInfo) { - RenderLayer* reflectionLayer = m_reflectionInfo->reflectionLayer(); - if (!reflectionLayer->hasCompositedLayerMapping()) { - IntRect childUnionBounds = reflectionLayer->calculateLayerBounds(this, 0, descendantFlags); - unionBounds.unite(childUnionBounds); - } - } + if (m_reflectionInfo && !m_reflectionInfo->reflectionLayer()->hasCompositedLayerMapping()) + result.unite(m_reflectionInfo->reflectionLayer()->boundingBoxForCompositing(this)); - ASSERT(m_stackingNode->isStackingContainer() || !m_stackingNode->hasPositiveZOrderList()); + ASSERT(m_stackingNode->isStackingContext() || !m_stackingNode->hasPositiveZOrderList()); -#if !ASSERT_DISABLED +#if ASSERT_ENABLED LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(this)->stackingNode()); #endif - // FIXME: Descendants that are composited should not necessarily be skipped, if they don't paint into their own - // separate backing. Instead, they ought to contribute to the bounds of the layer we're trying to compute. - // This applies to all z-order lists below. - RenderLayerStackingNodeIterator iterator(*m_stackingNode.get(), AllChildren); - while (RenderLayerStackingNode* node = iterator.next()) { - // Node's compositing ancestor may have changed its draw content status - // prior to updating its bounds. The requires-own-backing-store-for-ancestor-reasons - // could be stale. Refresh them now. - if (node->layer()->hasCompositedLayerMapping()) { - RenderLayer* enclosingCompositingLayer = node->layer()->enclosingCompositingLayer(false); - node->layer()->compositedLayerMapping()->updateRequiresOwnBackingStoreForAncestorReasons(enclosingCompositingLayer); - } - - if (flags & IncludeCompositedDescendants || !node->layer()->hasCompositedLayerMapping()) { - IntRect childUnionBounds = node->layer()->calculateLayerBounds(this, 0, descendantFlags); - unionBounds.unite(childUnionBounds); - } - } + // Reflections are implemented with RenderLayers that hang off of the reflected layer. However, + // the reflection layer subtree does not include the subtree of the parent RenderLayer, so + // a recursive computation of stacking children yields no results. This breaks cases when there are stacking + // children of the parent, that need to be included in reflected composited bounds. + // Fix this by including composited bounds of stacking children of the reflected RenderLayer. + if (parent() && parent()->reflectionInfo() && parent()->reflectionInfo()->reflectionLayer() == this) + expandCompositingRectForStackingChildren(parent(), options, result); + else + expandCompositingRectForStackingChildren(this, options, result); // 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) - renderer->style()->filterOutsets().expandRect(unionBounds); - - if ((flags & IncludeSelfTransform) && shouldIncludeTransform) { - TransformationMatrix* affineTrans = transform(); - boundingBoxRect = affineTrans->mapRect(boundingBoxRect); - unionBounds = affineTrans->mapRect(unionBounds); - } + m_renderer->style()->filterOutsets().expandRect(result); - LayoutPoint ancestorRelOffset; - if (offsetFromRoot) - ancestorRelOffset = *offsetFromRoot; - else - convertToLayerCoords(ancestorLayer, ancestorRelOffset); - unionBounds.moveBy(ancestorRelOffset); + if (shouldIncludeTransform) + result = transform()->mapRect(result); - return pixelSnappedIntRect(unionBounds); + LayoutPoint delta; + convertToLayerCoords(ancestorLayer, delta); + result.moveBy(delta); + return result; } CompositingState RenderLayer::compositingState() const { + ASSERT(isAllowedToQueryCompositingState()); + // This is computed procedurally so there is no redundant state variable that // can get out of sync from the real actual compositing state. @@ -3651,34 +3455,70 @@ CompositingState RenderLayer::compositingState() const if (!m_compositedLayerMapping) return NotComposited; - if (m_compositedLayerMapping && compositedLayerMapping()->paintsIntoCompositedAncestor()) + if (compositedLayerMapping()->paintsIntoCompositedAncestor()) return HasOwnBackingButPaintsIntoAncestor; - ASSERT(m_compositedLayerMapping); return PaintsIntoOwnBacking; } +bool RenderLayer::isAllowedToQueryCompositingState() const +{ + if (gCompositingQueryMode == CompositingQueriesAreAllowed) + return true; + return renderer()->document().lifecycle().state() >= DocumentLifecycle::InCompositingUpdate; +} + +CompositedLayerMappingPtr RenderLayer::compositedLayerMapping() const +{ + ASSERT(isAllowedToQueryCompositingState()); + return m_compositedLayerMapping.get(); +} + CompositedLayerMappingPtr RenderLayer::ensureCompositedLayerMapping() { if (!m_compositedLayerMapping) { - m_compositedLayerMapping = adoptPtr(new CompositedLayerMapping(this)); + m_compositedLayerMapping = adoptPtr(new CompositedLayerMapping(*this)); + m_compositedLayerMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree); updateOrRemoveFilterEffectRenderer(); if (RuntimeEnabledFeatures::cssCompositingEnabled()) - compositedLayerMapping()->setBlendMode(m_blendMode); + compositedLayerMapping()->setBlendMode(m_blendInfo.blendMode()); } return m_compositedLayerMapping.get(); } void RenderLayer::clearCompositedLayerMapping(bool layerBeingDestroyed) { + if (!layerBeingDestroyed) { + // We need to make sure our decendants get a geometry update. In principle, + // we could call setNeedsGraphicsLayerUpdate on our children, but that would + // require walking the z-order lists to find them. Instead, we over-invalidate + // by marking our parent as needing a geometry update. + if (RenderLayer* compositingParent = enclosingCompositingLayer(ExcludeSelf)) + compositingParent->compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree); + } + m_compositedLayerMapping.clear(); if (!layerBeingDestroyed) updateOrRemoveFilterEffectRenderer(); } +void RenderLayer::setGroupedMapping(CompositedLayerMapping* groupedMapping, bool layerBeingDestroyed) +{ + if (groupedMapping == m_groupedMapping) + return; + + if (!layerBeingDestroyed && m_groupedMapping) { + m_groupedMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree); + m_groupedMapping->removeRenderLayerFromSquashingGraphicsLayer(this); + } + m_groupedMapping = groupedMapping; + if (!layerBeingDestroyed && m_groupedMapping) + m_groupedMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree); +} + bool RenderLayer::hasCompositedMask() const { return m_compositedLayerMapping && m_compositedLayerMapping->hasMaskLayer(); @@ -3703,6 +3543,11 @@ bool RenderLayer::paintsWithTransform(PaintBehavior paintBehavior) const return transform() && ((paintBehavior & PaintBehaviorFlattenCompositingLayers) || compositingState() != PaintsIntoOwnBacking); } +bool RenderLayer::paintsWithBlendMode() const +{ + return m_blendInfo.hasBlendMode() && compositingState() != PaintsIntoOwnBacking; +} + bool RenderLayer::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const { if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant()) @@ -3764,32 +3609,13 @@ bool RenderLayer::childBackgroundIsKnownToBeOpaqueInRect(const LayoutRect& local return false; } -void RenderLayer::setParent(RenderLayer* parent) -{ - if (parent == m_parent) - return; - - if (m_parent && !renderer()->documentBeingDestroyed()) - compositor()->layerWillBeRemoved(m_parent, this); - - m_parent = parent; - - if (m_parent && !renderer()->documentBeingDestroyed()) - compositor()->layerWasAdded(m_parent, this); -} - bool RenderLayer::shouldBeSelfPaintingLayer() const { - return !m_stackingNode->isNormalFlowOnly() + if (renderer()->isRenderPart() && toRenderPart(renderer())->requiresAcceleratedCompositing()) + return true; + return m_layerType == NormalLayer || (m_scrollableArea && m_scrollableArea->hasOverlayScrollbars()) - || needsCompositedScrolling() - || renderer()->hasReflection() - || renderer()->hasMask() - || renderer()->isTableRow() - || renderer()->isCanvas() - || renderer()->isVideo() - || renderer()->isEmbeddedObject() - || renderer()->isRenderIFrame(); + || needsCompositedScrolling(); } void RenderLayer::updateSelfPaintingLayer() @@ -3814,7 +3640,7 @@ bool RenderLayer::hasNonEmptyChildRenderers() const // <img src=...> // </div> // so test for 0x0 RenderTexts here - for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) { + for (RenderObject* child = renderer()->slowFirstChild(); child; child = child->nextSibling()) { if (!child->hasLayer()) { if (child->isRenderInline() || !child->isBox()) return true; @@ -3860,114 +3686,12 @@ bool RenderLayer::isVisuallyNonEmpty() const return false; } -void RenderLayer::updateVisibilityAfterStyleChange(const RenderStyle* oldStyle) -{ - if (!oldStyle || (oldStyle->visibility() != renderer()->style()->visibility())) - compositor()->setNeedsUpdateCompositingRequirementsState(); -} - -void RenderLayer::updateOutOfFlowPositioned(const RenderStyle* oldStyle) -{ - if (oldStyle && (renderer()->style()->position() == oldStyle->position())) - return; - - bool wasOutOfFlowPositioned = oldStyle && (oldStyle->position() == AbsolutePosition || oldStyle->position() == FixedPosition); - bool isOutOfFlowPositioned = renderer()->isOutOfFlowPositioned(); - if (!wasOutOfFlowPositioned && !isOutOfFlowPositioned) - return; - - // Even if the layer remains out-of-flow, a change to this property - // will likely change its containing block. We must clear these bits - // so that they can be set properly by the RenderLayerCompositor. - for (RenderLayer* ancestor = parent(); ancestor; ancestor = ancestor->parent()) - ancestor->setHasUnclippedDescendant(false); - - // Ensures that we reset the above bits correctly. - compositor()->setNeedsUpdateCompositingRequirementsState(); - - if (wasOutOfFlowPositioned && isOutOfFlowPositioned) - return; - - if (isOutOfFlowPositioned) { - setAncestorChainHasOutOfFlowPositionedDescendant(); - compositor()->addOutOfFlowPositionedLayer(this); - } else { - dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); - compositor()->removeOutOfFlowPositionedLayer(this); - - // We need to reset the isUnclippedDescendant bit here because normally - // the "unclipped-ness" property is only updated in - // RenderLayerCompositor::updateCompositingRequirementsState(). However, - // it is only updated for layers which are known to be out of flow. - // Since this is no longer out of flow, we have to explicitly ensure - // that it doesn't think it is unclipped. - setIsUnclippedDescendant(false); - } -} - static bool hasOrHadFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle) { ASSERT(newStyle); return (oldStyle && oldStyle->hasFilter()) || newStyle->hasFilter(); } -inline bool RenderLayer::needsCompositingLayersRebuiltForClip(const RenderStyle* oldStyle, const RenderStyle* newStyle) const -{ - ASSERT(newStyle); - return oldStyle && (oldStyle->clip() != newStyle->clip() || oldStyle->hasClip() != newStyle->hasClip()); -} - -inline bool RenderLayer::needsCompositingLayersRebuiltForOverflow(const RenderStyle* oldStyle, const RenderStyle* newStyle) const -{ - ASSERT(newStyle); - return !hasCompositedLayerMapping() && oldStyle && (oldStyle->overflowX() != newStyle->overflowX()) && m_stackingNode->ancestorStackingContainerNode()->layer()->hasCompositingDescendant(); -} - -inline bool RenderLayer::needsCompositingLayersRebuiltForFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle, bool didPaintWithFilters) const -{ - if (!hasOrHadFilters(oldStyle, newStyle)) - return false; - - if (RuntimeEnabledFeatures::webAnimationsCSSEnabled() - ? hasActiveAnimationsOnCompositor(*renderer(), CSSPropertyWebkitFilter) - : renderer()->animation().isRunningAcceleratedAnimationOnRenderer(renderer(), CSSPropertyWebkitFilter)) { - - // When the compositor is performing the filter animation, we shouldn't touch the compositing layers. - // All of the layers above us should have been promoted to compositing layers already. - return false; - } - - FilterOutsets newOutsets = newStyle->filterOutsets(); - if (oldStyle && (oldStyle->filterOutsets() != newOutsets)) { - // When filter outsets change, we need to: - // (1) Recompute the overlap map to promote the correct layers to composited layers. - // (2) Update the composited layer bounds (and child GraphicsLayer positions) on platforms - // whose compositors can't compute their own filter outsets. - return true; - } - -#if HAVE(COMPOSITOR_FILTER_OUTSETS) - if ((didPaintWithFilters != paintsWithFilters()) && !newOutsets.isZero()) { - // When the layer used to paint filters in software and now paints filters in the - // compositor, the compositing layer bounds need to change from including filter outsets to - // excluding filter outsets, on platforms whose compositors compute their own outsets. - // Similarly for the reverse change from compositor-painted to software-painted filters. - return true; - } -#endif - - return false; -} - -inline bool RenderLayer::needsCompositingLayersRebuiltForBlending(const RenderStyle* oldStyle, const RenderStyle* newStyle) const -{ - ASSERT(newStyle); - if (!hasCompositedLayerMapping()) - return false; - return (shouldIsolateCompositedDescendants() && !stackingNode()->isStackingContext()) - || (oldStyle && (oldStyle->hasBlendMode() != newStyle->hasBlendMode())); -} - void RenderLayer::updateFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle) { if (!hasOrHadFilters(oldStyle, newStyle)) @@ -3976,59 +3700,50 @@ void RenderLayer::updateFilters(const RenderStyle* oldStyle, const RenderStyle* updateOrRemoveFilterClients(); // During an accelerated animation, both WebKit and the compositor animate properties. // However, WebKit shouldn't ask the compositor to update its filters if the compositor is performing the animation. - if (hasCompositedLayerMapping() && (RuntimeEnabledFeatures::webAnimationsCSSEnabled() - ? !hasActiveAnimationsOnCompositor(*renderer(), CSSPropertyWebkitFilter) - : !renderer()->animation().isRunningAcceleratedAnimationOnRenderer(renderer(), CSSPropertyWebkitFilter))) + if (hasCompositedLayerMapping() && !newStyle->isRunningFilterAnimationOnCompositor()) compositedLayerMapping()->updateFilters(renderer()->style()); updateOrRemoveFilterEffectRenderer(); } -void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle) +void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle) { m_stackingNode->updateIsNormalFlowOnly(); + m_stackingNode->updateStackingNodesAfterStyleChange(oldStyle); if (m_scrollableArea) m_scrollableArea->updateAfterStyleChange(oldStyle); - m_stackingNode->updateStackingNodesAfterStyleChange(oldStyle); - updateVisibilityAfterStyleChange(oldStyle); + // Overlay scrollbars can make this layer self-painting so we need // to recompute the bit once scrollbars have been updated. updateSelfPaintingLayer(); - updateOutOfFlowPositioned(oldStyle); - updateReflectionInfo(oldStyle); + if (!oldStyle || !renderer()->style()->reflectionDataEquivalent(oldStyle)) { + ASSERT(!oldStyle || diff.needsFullLayout()); + updateReflectionInfo(oldStyle); + } if (RuntimeEnabledFeatures::cssCompositingEnabled()) - updateBlendMode(); + m_blendInfo.updateBlendMode(); updateDescendantDependentFlags(); - updateTransform(); - - bool didPaintWithFilters = false; - - if (paintsWithFilters()) - didPaintWithFilters = true; - updateFilters(oldStyle, renderer()->style()); - - const RenderStyle* newStyle = renderer()->style(); - if (compositor()->updateLayerCompositingState(this) - || needsCompositingLayersRebuiltForClip(oldStyle, newStyle) - || needsCompositingLayersRebuiltForOverflow(oldStyle, newStyle) - || needsCompositingLayersRebuiltForFilters(oldStyle, newStyle, didPaintWithFilters) - || needsCompositingLayersRebuiltForBlending(oldStyle, newStyle)) { - compositor()->setCompositingLayersNeedRebuild(); - } else if (compositingState() == PaintsIntoOwnBacking || compositingState() == HasOwnBackingButPaintsIntoAncestor) { - ASSERT(hasCompositedLayerMapping()); - compositedLayerMapping()->updateGraphicsLayerGeometry(); - } else if (compositingState() == PaintsIntoGroupedBacking) { - ASSERT(compositor()->layerSquashingEnabled()); - ASSERT(groupedMapping()); - // updateGraphicsLayerGeometry() is called to update the squashingLayer in case its size/position has changed. - // FIXME: Make sure to create a layout test that covers this scenario. - // FIXME: It is not expected that any other layers on the compositedLayerMapping would change. we should - // be able to just update the squashing layer only and save a lot of computation. - groupedMapping()->updateGraphicsLayerGeometry(); + + updateTransform(oldStyle, renderer()->style()); + + { + // https://code.google.com/p/chromium/issues/detail?id=343759 + DisableCompositingQueryAsserts disabler; + updateFilters(oldStyle, renderer()->style()); } + + compositor()->updateStyleDeterminedCompositingReasons(this); + + setNeedsCompositingInputsUpdate(); + + // FIXME: Remove incremental compositing updates after fixing the chicken/egg issues + // https://code.google.com/p/chromium/issues/detail?id=343756 + DisableCompositingQueryAsserts disabler; + + compositor()->updateLayerCompositingState(this, RenderLayerCompositor::UseChickenEggHacks); } bool RenderLayer::scrollsOverflow() const @@ -4039,13 +3754,6 @@ bool RenderLayer::scrollsOverflow() const return false; } -bool RenderLayer::isCSSCustomFilterEnabled() const -{ - // We only want to enable shaders if WebGL is also enabled on this platform. - const Settings* settings = renderer()->document().settings(); - return settings && RuntimeEnabledFeatures::cssCustomFilterEnabled() && settings->webGLEnabled(); -} - FilterOperations RenderLayer::computeFilterOperations(const RenderStyle* style) { const FilterOperations& filters = style->filter(); @@ -4057,48 +3765,19 @@ FilterOperations RenderLayer::computeFilterOperations(const RenderStyle* style) ReferenceFilterOperation* referenceOperation = toReferenceFilterOperation(filterOperation); // FIXME: Cache the ReferenceFilter if it didn't change. RefPtr<ReferenceFilter> referenceFilter = ReferenceFilter::create(); +#ifdef BLINK_SCALE_FILTERS_AT_RECORD_TIME float zoom = style->effectiveZoom() * WebCore::deviceScaleFactor(renderer()->frame()); - referenceFilter->setFilterResolution(FloatSize(zoom, zoom)); +#else + float zoom = style->effectiveZoom(); +#endif + referenceFilter->setAbsoluteTransform(AffineTransform().scale(zoom, zoom)); referenceFilter->setLastEffect(ReferenceFilterBuilder::build(referenceFilter.get(), renderer(), referenceFilter->sourceGraphic(), referenceOperation)); referenceOperation->setFilter(referenceFilter.release()); } } - if (!filters.hasCustomFilter()) - return filters; - - if (!isCSSCustomFilterEnabled()) { - // CSS Custom filters should not parse at all in this case, but there might be - // remaining styles that were parsed when the flag was enabled. Reproduces in DumpRenderTree - // because it resets the flag while the previous test is still loaded. - return FilterOperations(); - } - - FilterOperations outputFilters; - for (size_t i = 0; i < filters.size(); ++i) { - RefPtr<FilterOperation> filterOperation = filters.operations().at(i); - if (filterOperation->type() == FilterOperation::CUSTOM) { - // We have to wait until the program of CSS Shaders is loaded before setting it on the layer. - // Note that we will handle the loading of the shaders and repainting of the layer in updateOrRemoveFilterClients. - const CustomFilterOperation* customOperation = toCustomFilterOperation(filterOperation.get()); - RefPtr<CustomFilterProgram> program = customOperation->program(); - if (!program->isLoaded()) - continue; - - CustomFilterGlobalContext* globalContext = renderer()->view()->customFilterGlobalContext(); - RefPtr<CustomFilterValidatedProgram> validatedProgram = globalContext->getValidatedProgram(program->programInfo()); - if (!validatedProgram->isInitialized()) - continue; - - RefPtr<ValidatedCustomFilterOperation> validatedOperation = ValidatedCustomFilterOperation::create(validatedProgram.release(), - customOperation->parameters(), customOperation->meshRows(), customOperation->meshColumns(), customOperation->meshType()); - outputFilters.operations().append(validatedOperation.release()); - continue; - } - outputFilters.operations().append(filterOperation.release()); - } - return outputFilters; + return filters; } void RenderLayer::updateOrRemoveFilterClients() @@ -4108,11 +3787,6 @@ void RenderLayer::updateOrRemoveFilterClients() return; } - if (renderer()->style()->filter().hasCustomFilter()) - ensureFilterInfo()->updateCustomFilterClients(renderer()->style()->filter()); - else if (hasFilterInfo()) - filterInfo()->removeCustomFilterClients(); - if (renderer()->style()->filter().hasReferenceFilter()) ensureFilterInfo()->updateReferenceFilterClients(renderer()->style()->filter()); else if (hasFilterInfo()) @@ -4128,7 +3802,7 @@ void RenderLayer::updateOrRemoveFilterEffectRenderer() // 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); + filterInfo->setRenderer(nullptr); return; } @@ -4136,7 +3810,6 @@ void RenderLayer::updateOrRemoveFilterEffectRenderer() RenderLayerFilterInfo* filterInfo = ensureFilterInfo(); if (!filterInfo->renderer()) { RefPtr<FilterEffectRenderer> filterRenderer = FilterEffectRenderer::create(); - filterRenderer->setIsAccelerated(renderer()->frame()->settings()->acceleratedFiltersEnabled()); filterInfo->setRenderer(filterRenderer.release()); // We can optimize away code paths in other places if we know that there are no software filters. @@ -4146,43 +3819,71 @@ void RenderLayer::updateOrRemoveFilterEffectRenderer() // 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(), computeFilterOperations(renderer()->style()))) - filterInfo->setRenderer(0); + filterInfo->setRenderer(nullptr); } void RenderLayer::filterNeedsRepaint() { - toElement(renderer()->node())->scheduleLayerUpdate(); - if (renderer()->view()) - renderer()->repaint(); + { + DeprecatedScheduleStyleRecalcDuringLayout marker(renderer()->document().lifecycle()); + // It's possible for scheduleSVGFilterLayerUpdateHack to schedule a style recalc, which + // is a problem because this function can be called while performing layout. + // Presumably this represents an illegal data flow of layout or compositing + // information into the style system. + toElement(renderer()->node())->scheduleSVGFilterLayerUpdateHack(); + } + + if (renderer()->view()) { + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && renderer()->frameView()->isInPerformLayout()) + renderer()->setShouldDoFullPaintInvalidationAfterLayout(true); + else + renderer()->paintInvalidationForWholeRenderer(); + } } void RenderLayer::addLayerHitTestRects(LayerHitTestRects& rects) const { + computeSelfHitTestRects(rects); + for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) + child->addLayerHitTestRects(rects); +} + +void RenderLayer::computeSelfHitTestRects(LayerHitTestRects& rects) const +{ if (!size().isEmpty()) { Vector<LayoutRect> rect; if (renderBox() && renderBox()->scrollsOverflow()) { // For scrolling layers, rects are taken to be in the space of the contents. - // We need to include both the entire contents, and also the bounding box - // of the layer in the space of it's parent (eg. for border / scroll bars). - rect.append(m_scrollableArea->overflowRect()); + // We need to include the bounding box of the layer in the space of its parent + // (eg. for border / scroll bars) and if it's composited then the entire contents + // as well as they may be on another composited layer. Skip reporting contents + // for non-composited layers as they'll get projected to the same layer as the + // bounding box. + if (compositingState() != NotComposited) + rect.append(m_scrollableArea->overflowRect()); + rects.set(this, rect); if (const RenderLayer* parentLayer = parent()) { LayerHitTestRects::iterator iter = rects.find(parentLayer); - if (iter == rects.end()) - iter = rects.add(parentLayer, Vector<LayoutRect>()).iterator; - iter->value.append(boundingBox(parentLayer)); + if (iter == rects.end()) { + rects.add(parentLayer, Vector<LayoutRect>()).storedValue->value.append(physicalBoundingBox(parentLayer)); + } else { + iter->value.append(physicalBoundingBox(parentLayer)); + } } } else { - rect.append(localBoundingBox()); + rect.append(logicalBoundingBox()); rects.set(this, rect); } } - - for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) - child->addLayerHitTestRects(rects); } +DisableCompositingQueryAsserts::DisableCompositingQueryAsserts() + : m_disabler(gCompositingQueryMode, CompositingQueriesAreAllowed) { } + +COMPILE_ASSERT(1 << RenderLayer::ViewportConstrainedNotCompositedReasonBits >= RenderLayer::NumNotCompositedReasons, too_many_viewport_constrained_not_compositing_reasons); + } // namespace WebCore #ifndef NDEBUG @@ -4191,7 +3892,7 @@ void showLayerTree(const WebCore::RenderLayer* layer) if (!layer) return; - if (WebCore::Frame* frame = layer->renderer()->frame()) { + if (WebCore::LocalFrame* frame = layer->renderer()->frame()) { WTF::String output = externalRepresentation(frame, WebCore::RenderAsTextShowAllLayers | WebCore::RenderAsTextShowLayerNesting | WebCore::RenderAsTextShowCompositedLayers | WebCore::RenderAsTextShowAddresses | WebCore::RenderAsTextShowIDAndClass | WebCore::RenderAsTextDontUpdateLayout | WebCore::RenderAsTextShowLayoutState); fprintf(stderr, "%s\n", output.utf8().data()); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayer.h b/chromium/third_party/WebKit/Source/core/rendering/RenderLayer.h index 06dd644f8b7..6e43a0b7fe5 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayer.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayer.h @@ -45,11 +45,10 @@ #ifndef RenderLayer_h #define RenderLayer_h -#include "core/rendering/CompositedLayerMappingPtr.h" -#include "core/rendering/CompositingReasons.h" +#include "core/rendering/compositing/CompositedLayerMappingPtr.h" #include "core/rendering/LayerPaintingInfo.h" -#include "core/rendering/PaintInfo.h" #include "core/rendering/RenderBox.h" +#include "core/rendering/RenderLayerBlendInfo.h" #include "core/rendering/RenderLayerClipper.h" #include "core/rendering/RenderLayerFilterInfo.h" #include "core/rendering/RenderLayerReflectionInfo.h" @@ -57,6 +56,7 @@ #include "core/rendering/RenderLayerScrollableArea.h" #include "core/rendering/RenderLayerStackingNode.h" #include "core/rendering/RenderLayerStackingNodeIterator.h" +#include "platform/graphics/CompositingReasons.h" #include "wtf/OwnPtr.h" namespace WebCore { @@ -66,29 +66,32 @@ class FilterOperations; class HitTestRequest; class HitTestResult; class HitTestingTransformState; -class PlatformEvent; -class RenderFlowThread; -class RenderGeometryMap; class CompositedLayerMapping; class RenderLayerCompositor; -class RenderReplica; -class RenderScrollbarPart; class RenderStyle; -class RenderView; -class Scrollbar; class TransformationMatrix; enum BorderRadiusClippingRule { IncludeSelfForBorderRadius, DoNotIncludeSelfForBorderRadius }; +enum IncludeSelfOrNot { IncludeSelf, ExcludeSelf }; -class RenderLayer { +enum CompositingQueryMode { + CompositingQueriesAreAllowed, + CompositingQueriesAreOnlyAllowedInCertainDocumentLifecyclePhases +}; + +// FIXME: remove this once the compositing query ASSERTS are no longer hit. +class DisableCompositingQueryAsserts { + WTF_MAKE_NONCOPYABLE(DisableCompositingQueryAsserts); public: - friend class RenderReplica; - // FIXME: Needed until we move all the necessary bits to the new class. - friend class RenderLayerStackingNode; - // FIXME: Needed until we move all the necessary bits to the new class. - friend class RenderLayerScrollableArea; + DisableCompositingQueryAsserts(); +private: + TemporaryChange<CompositingQueryMode> m_disabler; +}; - RenderLayer(RenderLayerModelObject*); +class RenderLayer { + WTF_MAKE_NONCOPYABLE(RenderLayer); +public: + RenderLayer(RenderLayerModelObject*, LayerType); ~RenderLayer(); String debugName() const; @@ -101,6 +104,8 @@ public: RenderLayer* firstChild() const { return m_first; } RenderLayer* lastChild() const { return m_last; } + const RenderLayer* compositingContainer() const; + void addChild(RenderLayer* newChild, RenderLayer* beforeChild = 0); RenderLayer* removeChild(RenderLayer*); @@ -111,11 +116,13 @@ public: bool isSelfPaintingLayer() const { return m_isSelfPaintingLayer; } + void setLayerType(LayerType layerType) { m_layerType = layerType; } + bool cannotBlitToWindow() const; - bool isTransparent() const; + bool isTransparent() const { return renderer()->isTransparent() || renderer()->hasMask(); } RenderLayer* transparentPaintingAncestor(); - void beginTransparencyLayers(GraphicsContext*, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior); + void beginTransparencyLayers(GraphicsContext*, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, PaintBehavior); bool isReflection() const { return renderer()->isReplica(); } RenderLayerReflectionInfo* reflectionInfo() { return m_reflectionInfo.get(); } @@ -145,35 +152,34 @@ public: // Allows updates of layer content without repainting. void contentChanged(ContentChangeType); - bool canRender3DTransforms() const; - enum UpdateLayerPositionsFlag { CheckForRepaint = 1 << 0, NeedsFullRepaintInBacking = 1 << 1, - IsCompositingUpdateRoot = 1 << 2, - UpdateCompositingLayers = 1 << 3, - UpdatePagination = 1 << 4 + UpdatePagination = 1 << 2, + ForceMayNeedPaintInvalidation = 1 << 3, }; typedef unsigned UpdateLayerPositionsFlags; - static const UpdateLayerPositionsFlags defaultFlags = CheckForRepaint | IsCompositingUpdateRoot | UpdateCompositingLayers; void updateLayerPositionsAfterLayout(const RenderLayer* rootLayer, UpdateLayerPositionsFlags); - void updateLayerPositionsAfterOverflowScroll(); void updateLayerPositionsAfterDocumentScroll(); + // FIXME: Should updateLayerPositions be private? + void updateLayerPositionRecursive(UpdateLayerPositionsFlags = CheckForRepaint); + bool isPaginated() const { return m_isPaginated; } RenderLayer* enclosingPaginationLayer() const { return m_enclosingPaginationLayer; } - void updateTransform(); - - void updateBlendMode(); + void updateTransformationMatrix(); + RenderLayer* renderingContextRoot(); const LayoutSize& offsetForInFlowPosition() const { return m_offsetForInFlowPosition; } + void blockSelectionGapsBoundsChanged(); void addBlockSelectionGapsBounds(const LayoutRect&); void clearBlockSelectionGapsBounds(); void repaintBlockSelectionGaps(); + IntRect blockSelectionGapsBounds() const; bool hasBlockSelectionGapBounds() const; RenderLayerStackingNode* stackingNode() { return m_stackingNode.get(); } @@ -200,46 +206,30 @@ public: // Part of the issue is with subtree relayout: we don't check if our ancestors have some descendant flags dirty, missing some updates. bool hasSelfPaintingLayerDescendant() const { return m_hasSelfPaintingLayerDescendant; } - // FIXME: We should ASSERT(!m_hasOutOfFlowPositionedDescendantDirty) here. See above. - bool hasOutOfFlowPositionedDescendant() const { return m_hasOutOfFlowPositionedDescendant; } - - void setHasOutOfFlowPositionedDescendant(bool hasDescendant) { m_hasOutOfFlowPositionedDescendant = hasDescendant; } - void setHasOutOfFlowPositionedDescendantDirty(bool dirty) { m_hasOutOfFlowPositionedDescendantDirty = dirty; } - - bool childLayerHasBlendMode() const { ASSERT(!m_childLayerHasBlendModeStatusDirty); return m_childLayerHasBlendMode; } - - bool hasUnclippedDescendant() const { return m_hasUnclippedDescendant; } - void setHasUnclippedDescendant(bool hasDescendant) { m_hasUnclippedDescendant = hasDescendant; } - void updateHasUnclippedDescendant(); - bool isUnclippedDescendant() const { return m_isUnclippedDescendant; } - + // Will ensure that hasNonCompositiedChild are up to date. + void updateScrollingStateAfterCompositingChange(); bool hasVisibleNonLayerContent() const { return m_hasVisibleNonLayerContent; } - void updateHasVisibleNonLayerContent(); + bool hasNonCompositedChild() const { ASSERT(isAllowedToQueryCompositingState()); return m_hasNonCompositedChild; } + + bool usedTransparency() const { return m_usedTransparency; } // Gets the nearest enclosing positioned ancestor layer (also includes // the <html> layer and the root layer). RenderLayer* enclosingPositionedAncestor() const; - // Returns the nearest enclosing layer that is scrollable. - RenderLayer* enclosingScrollableLayer() const; - - // The layer relative to which clipping rects for this layer are computed. - RenderLayer* clippingRootForPainting() const; + RenderLayer* enclosingOverflowClipLayer(IncludeSelfOrNot = IncludeSelf) const; + bool isRepaintContainer() const; // Enclosing compositing layer; if includeSelf is true, may return this. - RenderLayer* enclosingCompositingLayer(bool includeSelf = true) const; - RenderLayer* enclosingCompositingLayerForRepaint(bool includeSelf = true) const; + RenderLayer* enclosingCompositingLayer(IncludeSelfOrNot = IncludeSelf) const; + RenderLayer* enclosingCompositingLayerForRepaint(IncludeSelfOrNot = IncludeSelf) const; // Ancestor compositing layer, excluding this. - RenderLayer* ancestorCompositingLayer() const { return enclosingCompositingLayer(false); } - - // Ancestor composited scrolling layer at or above our containing block. - RenderLayer* ancestorCompositedScrollingLayer() const; + RenderLayer* ancestorCompositingLayer() const { return enclosingCompositingLayer(ExcludeSelf); } // Ancestor scrolling layer at or above our containing block. RenderLayer* ancestorScrollingLayer() const; - RenderLayer* enclosingFilterLayer(bool includeSelf = true) const; - RenderLayer* enclosingFilterRepaintLayer() const; + RenderLayer* enclosingFilterLayer(IncludeSelfOrNot = IncludeSelf) const; bool hasAncestorWithFilterOutsets() const; bool canUseConvertToLayerCoords() const @@ -248,8 +238,6 @@ public: return !renderer()->hasColumns() && !renderer()->hasTransform() && !renderer()->isSVGRoot(); } - void convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& location) const; - void convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntRect&) const; void convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint& location) const; void convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutRect&) const; @@ -257,58 +245,31 @@ public: // paints the layers that intersect the damage rect from back to // front. The hitTest method looks for mouse events by walking // layers that intersect the point from front to back. - void paint(GraphicsContext*, const LayoutRect& damageRect, PaintBehavior = PaintBehaviorNormal, RenderObject* paintingRoot = 0, - RenderRegion* = 0, PaintLayerFlags = 0); + // paint() assumes that the caller will clip to the bounds of damageRect if necessary. + void paint(GraphicsContext*, const LayoutRect& damageRect, PaintBehavior = PaintBehaviorNormal, RenderObject* paintingRoot = 0, PaintLayerFlags = 0); bool hitTest(const HitTestRequest&, HitTestResult&); bool hitTest(const HitTestRequest&, const HitTestLocation&, HitTestResult&); void paintOverlayScrollbars(GraphicsContext*, const LayoutRect& damageRect, PaintBehavior, RenderObject* paintingRoot = 0); - // This method figures out our layerBounds in coordinates relative to - // |rootLayer}. It also computes our background and foreground clip rects - // for painting/event handling. - // Pass offsetFromRoot if known. - void calculateRects(const ClipRectsContext&, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, - ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, const LayoutPoint* offsetFromRoot = 0) const; - - 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. - // Pass offsetFromRoot if known. bool intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot = 0) const; - enum CalculateLayerBoundsFlag { - IncludeSelfTransform = 1 << 0, - UseLocalClipRectIfPossible = 1 << 1, - IncludeLayerFilterOutsets = 1 << 2, - ExcludeHiddenDescendants = 1 << 3, - DontConstrainForMask = 1 << 4, - IncludeCompositedDescendants = 1 << 5, - UseFragmentBoxes = 1 << 6, - PretendLayerHasOwnBacking = 1 << 7, - DefaultCalculateLayerBoundsFlags = IncludeSelfTransform | UseLocalClipRectIfPossible | IncludeLayerFilterOutsets | UseFragmentBoxes - }; - typedef unsigned CalculateLayerBoundsFlags; - // Bounding box relative to some ancestor layer. Pass offsetFromRoot if known. - LayoutRect boundingBox(const RenderLayer* rootLayer, CalculateLayerBoundsFlags = 0, const LayoutPoint* offsetFromRoot = 0) const; - // Bounding box in the coordinates of this layer. - LayoutRect localBoundingBox(CalculateLayerBoundsFlags = 0) const; - // Pixel snapped bounding box relative to the root. - IntRect absoluteBoundingBox() const; + LayoutRect physicalBoundingBox(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot = 0) const; + LayoutRect physicalBoundingBoxIncludingReflectionAndStackingChildren(const RenderLayer* ancestorLayer, const LayoutPoint& offsetFromRoot) const; - // Bounds used for layer overlap testing in RenderLayerCompositor. - LayoutRect overlapBounds() const { return overlapBoundsIncludeChildren() ? calculateLayerBounds(this) : localBoundingBox(); } + // FIXME: This function is inconsistent as to whether the returned rect has been flipped for writing mode. + LayoutRect boundingBoxForCompositingOverlapTest() const { return overlapBoundsIncludeChildren() ? boundingBoxForCompositing() : logicalBoundingBox(); } // If true, this layer's children are included in its bounds for overlap testing. // We can't rely on the children's positions if this layer has a filter that could have moved the children's pixels around. bool overlapBoundsIncludeChildren() const { return hasFilter() && renderer()->style()->filter().hasFilterThatMovesPixels(); } - // Can pass offsetFromRoot if known. - IntRect calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot = 0, CalculateLayerBoundsFlags = DefaultCalculateLayerBoundsFlags) const; - - // WARNING: This method returns the offset for the parent as this is what updateLayerPositions expects. - LayoutPoint computeOffsetFromRoot(bool& hasLayerOffset) const; + enum CalculateBoundsOptions { + ApplyBoundsChickenEggHacks, + DoNotApplyBoundsChickenEggHacks, + }; + LayoutRect boundingBoxForCompositing(const RenderLayer* ancestorLayer = 0, CalculateBoundsOptions = DoNotApplyBoundsChickenEggHacks) const; LayoutUnit staticInlinePosition() const { return m_staticInlinePosition; } LayoutUnit staticBlockPosition() const { return m_staticBlockPosition; } @@ -316,6 +277,9 @@ public: void setStaticInlinePosition(LayoutUnit position) { m_staticInlinePosition = position; } void setStaticBlockPosition(LayoutUnit position) { m_staticBlockPosition = position; } + LayoutSize subpixelAccumulation() const; + void setSubpixelAccumulation(const LayoutSize&); + bool hasTransform() const { return renderer()->hasTransform(); } // Note that this transform has the transform-origin baked in. TransformationMatrix* transform() const { return m_transform.get(); } @@ -333,11 +297,13 @@ public: bool preserves3D() const { return renderer()->style()->transformStyle3D() == TransformStyle3DPreserve3D; } bool has3DTransform() const { return m_transform && !m_transform->isAffine(); } + // FIXME: reflections should force transform-style to be flat in the style: https://bugs.webkit.org/show_bug.cgi?id=106959 + bool shouldPreserve3D() const { return !renderer()->hasReflection() && renderer()->style()->transformStyle3D() == TransformStyle3DPreserve3D; } + void filterNeedsRepaint(); bool hasFilter() const { return renderer()->hasFilter(); } - bool hasBlendMode() const; - bool paintsWithBlendMode() const { return hasBlendMode() && compositingState() != PaintsIntoOwnBacking; } + bool paintsWithBlendMode() const; void* operator new(size_t); // Only safe to call from RenderLayerModelObject::destroyLayer() @@ -345,7 +311,11 @@ public: CompositingState compositingState() const; - CompositedLayerMappingPtr compositedLayerMapping() const { return m_compositedLayerMapping.get(); } + // This returns true if our document is in a phase of its lifestyle during which + // compositing state may legally be read. + bool isAllowedToQueryCompositingState() const; + + CompositedLayerMappingPtr compositedLayerMapping() const; CompositedLayerMappingPtr ensureCompositedLayerMapping(); // NOTE: If you are using hasCompositedLayerMapping to determine the state of compositing for this layer, @@ -355,7 +325,7 @@ public: void clearCompositedLayerMapping(bool layerBeingDestroyed = false); CompositedLayerMapping* groupedMapping() const { return m_groupedMapping; } - void setGroupedMapping(CompositedLayerMapping* groupedMapping) { m_groupedMapping = groupedMapping; } + void setGroupedMapping(CompositedLayerMapping* groupedMapping, bool layerBeingDestroyed = false); bool hasCompositedMask() const; bool hasCompositedClippingMask() const; @@ -366,10 +336,16 @@ public: RenderLayer* scrollParent() const; RenderLayer* clipParent() const; - bool needsCompositingLayersRebuiltForClip(const RenderStyle* oldStyle, const RenderStyle* newStyle) const; - bool needsCompositingLayersRebuiltForOverflow(const RenderStyle* oldStyle, const RenderStyle* newStyle) const; - bool needsCompositingLayersRebuiltForFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle, bool didPaintWithFilters) const; - bool needsCompositingLayersRebuiltForBlending(const RenderStyle* oldStyle, const RenderStyle* newStyle) const; + // Computes the position of the given render object in the space of |repaintContainer|. + // FIXME: invert the logic to have repaint containers take care of painting objects into them, rather than the reverse. + // This will allow us to clean up this static method messiness. + static LayoutPoint positionFromPaintInvalidationContainer(const RenderObject*, const RenderLayerModelObject* repaintContainer); + + // Adjusts the given rect (in the coordinate space of the RenderObject) to the coordinate space of |repaintContainer|'s GraphicsLayer backing. + static void mapRectToRepaintBacking(const RenderObject*, const RenderLayerModelObject* repaintContainer, LayoutRect&); + + // Computes the bounding repaint rect for |renderObject|, in the coordinate space of |repaintContainer|'s GraphicsLayer backing. + static LayoutRect computeRepaintRect(const RenderObject*, const RenderLayer* repaintContainer); bool paintsWithTransparency(PaintBehavior paintBehavior) const { @@ -385,8 +361,6 @@ public: bool containsDirtyOverlayScrollbars() const { return m_containsDirtyOverlayScrollbars; } void setContainsDirtyOverlayScrollbars(bool dirtyScrollbars) { m_containsDirtyOverlayScrollbars = dirtyScrollbars; } - bool isCSSCustomFilterEnabled() const; - FilterOperations computeFilterOperations(const RenderStyle*); bool paintsWithFilters() const; bool requiresFullLayerImageForFilters() const; @@ -412,29 +386,36 @@ public: Node* enclosingElement() const; bool isInTopLayer() const; - bool isInTopLayerSubtree() const; enum ViewportConstrainedNotCompositedReason { - NoNotCompositedReason, + NoNotCompositedReason = 0, NotCompositedForBoundsOutOfView, NotCompositedForNonViewContainer, NotCompositedForNoVisibleContent, NotCompositedForUnscrollableAncestors, - }; + NumNotCompositedReasons, - void setViewportConstrainedNotCompositedReason(ViewportConstrainedNotCompositedReason reason) { m_compositingProperties.viewportConstrainedNotCompositedReason = reason; } - ViewportConstrainedNotCompositedReason viewportConstrainedNotCompositedReason() const { return static_cast<ViewportConstrainedNotCompositedReason>(m_compositingProperties.viewportConstrainedNotCompositedReason); } + // This is the number of bits used to store the viewport constrained not composited + // reasons. We define this constant since sizeof won't return the number of bits, and we + // shouldn't duplicate the constant. + ViewportConstrainedNotCompositedReasonBits = 3 + }; - bool isOutOfFlowRenderFlowThread() const { return renderer()->isOutOfFlowRenderFlowThread(); } + void setViewportConstrainedNotCompositedReason(ViewportConstrainedNotCompositedReason reason) { m_viewportConstrainedNotCompositedReason = reason; } + ViewportConstrainedNotCompositedReason viewportConstrainedNotCompositedReason() const { ASSERT(isAllowedToQueryCompositingState()); return static_cast<ViewportConstrainedNotCompositedReason>(m_viewportConstrainedNotCompositedReason); } bool scrollsWithRespectTo(const RenderLayer*) const; void addLayerHitTestRects(LayerHitTestRects&) const; + // Compute rects only for this layer + void computeSelfHitTestRects(LayerHitTestRects&) const; + // FIXME: This should probably return a ScrollableArea but a lot of internal methods are mistakenly exposed. RenderLayerScrollableArea* scrollableArea() const { return m_scrollableArea.get(); } RenderLayerRepainter& repainter() { return m_repainter; } RenderLayerClipper& clipper() { return m_clipper; } + const RenderLayerClipper& clipper() const { return m_clipper; } inline bool isPositionedContainer() const { @@ -445,45 +426,87 @@ public: return isRootLayer() || layerRenderer->isPositioned() || hasTransform(); } + // paintLayer() assumes that the caller will clip to the bounds of the painting dirty if necessary. void paintLayer(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags); PassOwnPtr<Vector<FloatRect> > collectTrackedRepaintRects() const; - void setOffsetFromSquashingLayerOrigin(IntSize offset) { m_compositingProperties.offsetFromSquashingLayerOrigin = offset; } - IntSize offsetFromSquashingLayerOrigin() const { return m_compositingProperties.offsetFromSquashingLayerOrigin; } + RenderLayerBlendInfo& blendInfo() { return m_blendInfo; } -private: - bool hasOverflowControls() const; + void setOffsetFromSquashingLayerOrigin(IntSize offset) { m_offsetFromSquashingLayerOrigin = offset; } + IntSize offsetFromSquashingLayerOrigin() const { ASSERT(isAllowedToQueryCompositingState()); return m_offsetFromSquashingLayerOrigin; } - void setIsUnclippedDescendant(bool isUnclippedDescendant) { m_isUnclippedDescendant = isUnclippedDescendant; } + bool scrollsOverflow() const; - void setAncestorChainHasSelfPaintingLayerDescendant(); - void dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); + CompositingReasons styleDeterminedCompositingReasons() const { return m_styleDeterminedCompositingReasons; } + void setStyleDeterminedCompositingReasons(CompositingReasons reasons) { ASSERT(reasons == (reasons & CompositingReasonComboAllStyleDeterminedReasons)); m_styleDeterminedCompositingReasons = reasons; } - void setAncestorChainHasOutOfFlowPositionedDescendant(); - void dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus(); + class CompositingInputs { + public: + CompositingInputs() + : opacityAncestor(0) + , transformAncestor(0) + , filterAncestor(0) + , isUnclippedDescendant(false) + { } - bool acceleratedCompositingForOverflowScrollEnabled() const; - // FIXME: This is a temporary flag and should be removed once accelerated - // overflow scroll is ready (crbug.com/254111). - bool compositorDrivenAcceleratedScrollingEnabled() const; + IntRect clippedAbsoluteBoundingBox; + const RenderLayer* opacityAncestor; + const RenderLayer* transformAncestor; + const RenderLayer* filterAncestor; + unsigned isUnclippedDescendant : 1; + }; - void clipToRect(RenderLayer* rootLayer, GraphicsContext*, const LayoutRect& paintDirtyRect, const ClipRect&, - BorderRadiusClippingRule = IncludeSelfForBorderRadius); - void restoreClip(GraphicsContext*, const LayoutRect& paintDirtyRect, const ClipRect&); + void setNeedsCompositingInputsUpdate(); + bool childNeedsCompositingInputsUpdate() const { return m_childNeedsCompositingInputsUpdate; } + bool needsCompositingInputsUpdate() const { return m_needsCompositingInputsUpdate; } + + void updateCompositingInputs(const CompositingInputs&); + void clearChildNeedsCompositingInputsUpdate(); + + const CompositingInputs& compositingInputs() const { ASSERT(!m_needsCompositingInputsUpdate); return m_compositingInputs; } + + bool lostGroupedMapping() const { ASSERT(isAllowedToQueryCompositingState()); return m_lostGroupedMapping; } + void setLostGroupedMapping(bool b) { m_lostGroupedMapping = b; } + + CompositingReasons compositingReasons() const { ASSERT(isAllowedToQueryCompositingState()); return m_compositingReasons; } + void setCompositingReasons(CompositingReasons, CompositingReasons mask = CompositingReasonAll); + + bool hasCompositingDescendant() const { ASSERT(isAllowedToQueryCompositingState()); return m_hasCompositingDescendant; } + void setHasCompositingDescendant(bool); + + bool shouldIsolateCompositedDescendants() const { ASSERT(isAllowedToQueryCompositingState()); return m_shouldIsolateCompositedDescendants; } + void setShouldIsolateCompositedDescendants(bool); + + void updateDescendantDependentFlags(); + + void updateOrRemoveFilterEffectRenderer(); void updateSelfPaintingLayer(); - void updateVisibilityAfterStyleChange(const RenderStyle* oldStyle); - void updateOutOfFlowPositioned(const RenderStyle* oldStyle); + // paintLayerContents() assumes that the caller will clip to the bounds of the painting dirty rect if necessary. + void paintLayerContents(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags); + + RenderLayer* enclosingTransformedAncestor() const; + LayoutPoint computeOffsetFromTransformedAncestor() const; void didUpdateNeedsCompositedScrolling(); +private: + // Bounding box in the coordinates of this layer. + LayoutRect logicalBoundingBox() const; + + bool hasOverflowControls() const; + + void setAncestorChainHasSelfPaintingLayerDescendant(); + void dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); + + void clipToRect(const LayerPaintingInfo&, GraphicsContext*, const ClipRect&, PaintLayerFlags, BorderRadiusClippingRule = IncludeSelfForBorderRadius); + void restoreClip(GraphicsContext*, const LayoutRect& paintDirtyRect, const ClipRect&); + // Returns true if the position changed. bool updateLayerPosition(); - void updateLayerPositions(RenderGeometryMap* = 0, UpdateLayerPositionsFlags = defaultFlags); - enum UpdateLayerPositionsAfterScrollFlag { NoFlag = 0, IsOverflowScroll = 1 << 0, @@ -492,11 +515,10 @@ private: HasChangedAncestor = 1 << 3 }; typedef unsigned UpdateLayerPositionsAfterScrollFlags; - void updateLayerPositionsAfterScroll(RenderGeometryMap*, UpdateLayerPositionsAfterScrollFlags = NoFlag); + void updateLayerPositionsAfterScroll(UpdateLayerPositionsAfterScrollFlags = NoFlag); void setNextSibling(RenderLayer* next) { m_next = next; } void setPreviousSibling(RenderLayer* prev) { m_previous = prev; } - void setParent(RenderLayer* parent); void setFirstChild(RenderLayer* first) { m_first = first; } void setLastChild(RenderLayer* last) { m_last = last; } @@ -504,25 +526,30 @@ private: void paintLayerContentsAndReflection(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags); void paintLayerByApplyingTransform(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags, const LayoutPoint& translationOffset = LayoutPoint()); - void paintLayerContents(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags); + + // Returns whether this layer should be painted during sofware painting (i.e., not via calls from CompositedLayerMapping to draw into composited + // layers). + bool shouldPaintLayerInSoftwareMode(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags paintFlags); + void paintChildren(unsigned childrenToVisit, GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags); void paintPaginatedChildLayer(RenderLayer* childLayer, GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags); void paintChildLayerIntoColumns(RenderLayer* childLayer, GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags, const Vector<RenderLayer*>& columnLayers, size_t columnIndex); - void collectFragments(LayerFragments&, const RenderLayer* rootLayer, RenderRegion*, const LayoutRect& dirtyRect, + void collectFragments(LayerFragments&, const RenderLayer* rootLayer, const LayoutRect& dirtyRect, ClipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, - ShouldRespectOverflowClip = RespectOverflowClip, const LayoutPoint* offsetFromRoot = 0, const LayoutRect* layerBoundingBox = 0); + ShouldRespectOverflowClip = RespectOverflowClip, const LayoutPoint* offsetFromRoot = 0, + const LayoutSize& subPixelAccumulation = LayoutSize(), const LayoutRect* layerBoundingBox = 0); void updatePaintingInfoForFragments(LayerFragments&, const LayerPaintingInfo&, PaintLayerFlags, bool shouldPaintContent, const LayoutPoint* offsetFromRoot); void paintBackgroundForFragments(const LayerFragments&, GraphicsContext*, GraphicsContext* transparencyLayerContext, - const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo&, PaintBehavior, RenderObject* paintingRootForRenderer); + const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo&, PaintBehavior, RenderObject* paintingRootForRenderer, PaintLayerFlags); void paintForegroundForFragments(const LayerFragments&, GraphicsContext*, GraphicsContext* transparencyLayerContext, const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo&, PaintBehavior, RenderObject* paintingRootForRenderer, - bool selectionOnly, bool forceBlackText); - void paintForegroundForFragmentsWithPhase(PaintPhase, const LayerFragments&, GraphicsContext*, const LayerPaintingInfo&, PaintBehavior, RenderObject* paintingRootForRenderer); - void paintOutlineForFragments(const LayerFragments&, GraphicsContext*, const LayerPaintingInfo&, PaintBehavior, RenderObject* paintingRootForRenderer); - void paintOverflowControlsForFragments(const LayerFragments&, GraphicsContext*, const LayerPaintingInfo&); - void paintMaskForFragments(const LayerFragments&, GraphicsContext*, const LayerPaintingInfo&, RenderObject* paintingRootForRenderer); - void paintChildClippingMaskForFragments(const LayerFragments&, GraphicsContext*, const LayerPaintingInfo&, RenderObject* paintingRootForRenderer); + bool selectionOnly, bool forceBlackText, PaintLayerFlags); + void paintForegroundForFragmentsWithPhase(PaintPhase, const LayerFragments&, GraphicsContext*, const LayerPaintingInfo&, PaintBehavior, RenderObject* paintingRootForRenderer, PaintLayerFlags); + void paintOutlineForFragments(const LayerFragments&, GraphicsContext*, const LayerPaintingInfo&, PaintBehavior, RenderObject* paintingRootForRenderer, PaintLayerFlags); + void paintOverflowControlsForFragments(const LayerFragments&, GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags); + void paintMaskForFragments(const LayerFragments&, GraphicsContext*, const LayerPaintingInfo&, RenderObject* paintingRootForRenderer, PaintLayerFlags); + void paintChildClippingMaskForFragments(const LayerFragments&, GraphicsContext*, const LayerPaintingInfo&, RenderObject* paintingRootForRenderer, PaintLayerFlags); void paintTransformedLayerIntoFragments(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags); RenderLayer* hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result, @@ -557,7 +584,6 @@ private: bool shouldBeSelfPaintingLayer() const; -private: // FIXME: We should only create the stacking node if needed. bool requiresStackingNode() const { return true; } void updateStackingNode(); @@ -569,58 +595,29 @@ private: bool requiresScrollableArea() const { return renderBox(); } void updateScrollableArea(); - // Returns true our scrollable area is in the FrameView's collection of scrollable areas. This can - // only happen if we're both scrollable, and we do in fact overflow. - bool scrollsOverflow() const; - void dirtyAncestorChainVisibleDescendantStatus(); void setAncestorChainHasVisibleDescendant(); - void dirtyAncestorChainBlendedDescendantStatus(); - void setAncestorChainBlendedDescendant(); - - void updateDescendantDependentFlags(); - - // This flag is computed by RenderLayerCompositor, which knows more about 3d hierarchies than we do. - void setHas3DTransformedDescendant(bool b) { m_has3DTransformedDescendant = b; } - bool has3DTransformedDescendant() const { return m_has3DTransformedDescendant; } + void updateTransform(const RenderStyle* oldStyle, RenderStyle* newStyle); void dirty3DTransformedDescendantStatus(); // Both updates the status, and returns true if descendants of this have 3d. bool update3DTransformedDescendantStatus(); void updateOrRemoveFilterClients(); - void updateOrRemoveFilterEffectRenderer(); - - void parentClipRects(const ClipRectsContext&, ClipRects&) const; - ClipRect backgroundClipRect(const ClipRectsContext&) const; - LayoutRect paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior); - - RenderLayer* enclosingTransformedAncestor() const; + LayoutRect paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, PaintBehavior); void updatePagination(); // FIXME: Temporary. Remove when new columns come online. bool useRegionBasedColumns() const; - bool hasCompositingDescendant() const { return m_compositingProperties.hasCompositingDescendant; } - void setHasCompositingDescendant(bool b) { m_compositingProperties.hasCompositingDescendant = b; } - - bool hasNonCompositedChild() const { return m_compositingProperties.hasNonCompositedChild; } - void setHasNonCompositedChild(bool b) { m_compositingProperties.hasNonCompositedChild = b; } - - bool shouldIsolateCompositedDescendants() const { return m_compositingProperties.shouldIsolateCompositedDescendants; } - void setShouldIsolateCompositedDescendants(bool b) { m_compositingProperties.shouldIsolateCompositedDescendants = b; } - - void setCompositingReasons(CompositingReasons reasons) { m_compositingProperties.compositingReasons = reasons; } - CompositingReasons compositingReasons() const { return m_compositingProperties.compositingReasons; } + LayerType m_layerType; - friend class CompositedLayerMapping; - friend class RenderLayerCompositor; - friend class RenderLayerModelObject; - -protected: + // Self-painting layer is an optimization where we avoid the heavy RenderLayer painting + // machinery for a RenderLayer allocated only to handle the overflow clip case. + // FIXME(crbug.com/332791): Self-painting layer should be merged into the overflow-only concept. unsigned m_isSelfPaintingLayer : 1; // If have no self-painting descendants, we don't have to walk our children during painting. This can lead to @@ -628,26 +625,12 @@ protected: unsigned m_hasSelfPaintingLayerDescendant : 1; unsigned m_hasSelfPaintingLayerDescendantDirty : 1; - unsigned m_hasOutOfFlowPositionedDescendant : 1; - unsigned m_hasOutOfFlowPositionedDescendantDirty : 1; - - // This is true if we have an out-of-flow positioned descendant whose - // containing block is our ancestor. If this is the case, the descendant - // may fall outside of our clip preventing things like opting into - // composited scrolling (which causes clipping of all descendants). - unsigned m_hasUnclippedDescendant : 1; - - unsigned m_isUnclippedDescendant : 1; - const unsigned m_isRootLayer : 1; unsigned m_usedTransparency : 1; // Tracks whether we need to close a transparent layer, i.e., whether // we ended up painting this layer or any descendants (and therefore need to // blend). - unsigned m_childLayerHasBlendMode : 1; - unsigned m_childLayerHasBlendModeStatusDirty : 1; - unsigned m_visibleContentStatusDirty : 1; unsigned m_hasVisibleContent : 1; unsigned m_visibleDescendantStatusDirty : 1; @@ -670,8 +653,25 @@ protected: const unsigned m_canSkipRepaintRectsUpdateOnScroll : 1; unsigned m_hasFilterInfo : 1; + unsigned m_needsCompositingInputsUpdate : 1; + unsigned m_childNeedsCompositingInputsUpdate : 1; + + // Used only while determining what layers should be composited. Applies to the tree of z-order lists. + unsigned m_hasCompositingDescendant : 1; - blink::WebBlendMode m_blendMode; + // Applies to the real render layer tree (i.e., the tree determined by the layer's parent and children and + // as opposed to the tree formed by the z-order and normal flow lists). + unsigned m_hasNonCompositedChild : 1; + + // Should be for stacking contexts having unisolated blending descendants. + unsigned m_shouldIsolateCompositedDescendants : 1; + + // True if this render layer just lost its grouped mapping due to the CompositedLayerMapping being destroyed, + // and we don't yet know to what graphics layer this RenderLayer will be assigned. + unsigned m_lostGroupedMapping : 1; + + // The reason, if any exists, that a fixed-position layer is chosen not to be composited. + unsigned m_viewportConstrainedNotCompositedReason : ViewportConstrainedNotCompositedReasonBits; RenderLayerModelObject* m_renderer; @@ -699,46 +699,17 @@ protected: // Pointer to the enclosing RenderLayer that caused us to be paginated. It is 0 if we are not paginated. RenderLayer* m_enclosingPaginationLayer; - // Properties that are computed while updating compositing layers. These values may be dirty/invalid if - // compositing status is not up-to-date before using them. - struct CompositingProperties { - CompositingProperties() - : hasCompositingDescendant(false) - , hasNonCompositedChild(false) - , shouldIsolateCompositedDescendants(false) - , viewportConstrainedNotCompositedReason(NoNotCompositedReason) - , compositingReasons(CompositingReasonNone) - { } + // These compositing reasons are updated whenever style changes, not while updating compositing layers. + // They should not be used to infer the compositing state of this layer. + CompositingReasons m_styleDeterminedCompositingReasons; - // Used only while determining what layers should be composited. Applies to the tree of z-order lists. - bool hasCompositingDescendant : 1; + // Once computed, indicates all that a layer needs to become composited using the CompositingReasons enum bitfield. + CompositingReasons m_compositingReasons; - // Applies to the real render layer tree (i.e., the tree determined by the layer's parent and children and - // as opposed to the tree formed by the z-order and normal flow lists). - bool hasNonCompositedChild : 1; + // Used for invalidating this layer's contents on the squashing GraphicsLayer. + IntSize m_offsetFromSquashingLayerOrigin; - // Should be for stacking contexts having unisolated blending descendants. - bool shouldIsolateCompositedDescendants : 1; - - // The reason, if any exists, that a fixed-position layer is chosen not to be composited. - unsigned viewportConstrainedNotCompositedReason : 2; - - // Once computed, indicates all that a layer needs to become composited using the CompositingReasons enum bitfield. - CompositingReasons compositingReasons; - - // Used for invalidating this layer's contents on the squashing GraphicsLayer. - IntSize offsetFromSquashingLayerOrigin; - }; - - CompositingProperties m_compositingProperties; - -private: - enum CompositedScrollingHistogramBuckets { - IsScrollableAreaBucket = 0, - NeedsToBeStackingContainerBucket = 1, - WillUseCompositedScrollingBucket = 2, - CompositedScrollingHistogramMax = 3 - }; + CompositingInputs m_compositingInputs; IntRect m_blockSelectionGapsBounds; @@ -751,6 +722,9 @@ private: RenderLayerClipper m_clipper; // FIXME: Lazily allocate? OwnPtr<RenderLayerStackingNode> m_stackingNode; OwnPtr<RenderLayerReflectionInfo> m_reflectionInfo; + RenderLayerBlendInfo m_blendInfo; + + LayoutSize m_subpixelAccumulation; // The accumulated subpixel offset of a composited layer's composited bounds compared to absolute coordinates. }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerBlendInfo.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerBlendInfo.cpp new file mode 100644 index 00000000000..d8158b4cc40 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerBlendInfo.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. + * + * Portions are Copyright (C) 1998 Netscape Communications Corporation. + * + * Other contributors: + * Robert O'Callahan <roc+@cs.cmu.edu> + * David Baron <dbaron@fas.harvard.edu> + * Christian Biesinger <cbiesinger@web.de> + * Randall Jesup <rjesup@wgate.com> + * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de> + * Josh Soref <timeless@mac.com> + * Boris Zbarsky <bzbarsky@mit.edu> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Alternatively, the contents of this file may be used under the terms + * of either the Mozilla Public License Version 1.1, found at + * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public + * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html + * (the "GPL"), in which case the provisions of the MPL or the GPL are + * applicable instead of those above. If you wish to allow use of your + * version of this file only under the terms of one of those two + * licenses (the MPL or the GPL) and not to allow others to use your + * version of this file under the LGPL, indicate your decision by + * deletingthe provisions above and replace them with the notice and + * other provisions required by the MPL or the GPL, as the case may be. + * If you do not delete the provisions above, a recipient may use your + * version of this file under any of the LGPL, the MPL or the GPL. + */ + +#include "config.h" +#include "core/rendering/RenderLayerBlendInfo.h" + +#include "core/rendering/RenderLayer.h" +#include "core/rendering/RenderLayerModelObject.h" +#include "core/rendering/compositing/CompositedLayerMapping.h" + +namespace WebCore { + +RenderLayerBlendInfo::RenderLayerBlendInfo(RenderLayerModelObject& renderer) + : m_renderer(renderer) + , m_blendMode(blink::WebBlendModeNormal) + , m_childLayerHasBlendMode(false) + , m_childLayerHasBlendModeStatusDirty(false) +{ +} + +bool RenderLayerBlendInfo::hasBlendMode() const +{ + return RuntimeEnabledFeatures::cssCompositingEnabled() && m_renderer.hasBlendMode(); +} + +void RenderLayerBlendInfo::updateBlendMode() +{ + if (!RuntimeEnabledFeatures::cssCompositingEnabled()) + return; + + blink::WebBlendMode newBlendMode = m_renderer.style()->blendMode(); + if (newBlendMode == m_blendMode) + return; + + bool hadBlendMode = m_blendMode != blink::WebBlendModeNormal; + m_blendMode = newBlendMode; + + RenderLayer* layer = m_renderer.layer(); + // Only update the flag if a blend mode is set or unset. + if (layer->parent() && (!hadBlendMode || !hasBlendMode())) + layer->parent()->blendInfo().dirtyAncestorChainBlendedDescendantStatus(); + + if (layer->hasCompositedLayerMapping()) + layer->compositedLayerMapping()->setBlendMode(newBlendMode); +} + +void RenderLayerBlendInfo::dirtyAncestorChainBlendedDescendantStatus() +{ + for (RenderLayer* layer = m_renderer.layer(); layer; layer = layer->parent()) { + if (layer->blendInfo().childLayerHasBlendModeStatusDirty()) + break; + + layer->blendInfo().setChildLayerHasBlendModeStatusDirty(true); + + if (layer->stackingNode()->isStackingContext()) + break; + } +} + +void RenderLayerBlendInfo::setAncestorChainBlendedDescendant() +{ + for (RenderLayer* layer = m_renderer.layer(); layer; layer = layer->parent()) { + if (!layer->blendInfo().childLayerHasBlendModeStatusDirty() && layer->blendInfo().childLayerHasBlendMode()) + break; + + layer->blendInfo().setChildLayerHasBlendMode(true); + layer->blendInfo().setChildLayerHasBlendModeStatusDirty(false); + + if (layer->stackingNode()->isStackingContext()) + break; + } +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerBlendInfo.h b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerBlendInfo.h new file mode 100644 index 00000000000..6800baa6eef --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerBlendInfo.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2003, 2009, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * + * Portions are Copyright (C) 1998 Netscape Communications Corporation. + * + * Other contributors: + * Robert O'Callahan <roc+@cs.cmu.edu> + * David Baron <dbaron@fas.harvard.edu> + * Christian Biesinger <cbiesinger@web.de> + * Randall Jesup <rjesup@wgate.com> + * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de> + * Josh Soref <timeless@mac.com> + * Boris Zbarsky <bzbarsky@mit.edu> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Alternatively, the contents of this file may be used under the terms + * of either the Mozilla Public License Version 1.1, found at + * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public + * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html + * (the "GPL"), in which case the provisions of the MPL or the GPL are + * applicable instead of those above. If you wish to allow use of your + * version of this file only under the terms of one of those two + * licenses (the MPL or the GPL) and not to allow others to use your + * version of this file under the LGPL, indicate your decision by + * deletingthe provisions above and replace them with the notice and + * other provisions required by the MPL or the GPL, as the case may be. + * If you do not delete the provisions above, a recipient may use your + * version of this file under any of the LGPL, the MPL or the GPL. + */ + +#ifndef RenderLayerBlendInfo_h +#define RenderLayerBlendInfo_h + +#include "public/platform/WebBlendMode.h" +#include "wtf/Assertions.h" +#include "wtf/Noncopyable.h" + +namespace WebCore { + +class RenderLayerModelObject; + +class RenderLayerBlendInfo { + WTF_MAKE_NONCOPYABLE(RenderLayerBlendInfo); +public: + explicit RenderLayerBlendInfo(RenderLayerModelObject&); + + bool hasBlendMode() const; + void updateBlendMode(); + + bool childLayerHasBlendMode() const + { + ASSERT(!m_childLayerHasBlendModeStatusDirty); + return m_childLayerHasBlendMode; + } + bool childLayerHasBlendModeWhileDirty() const { return m_childLayerHasBlendMode; } + + void setChildLayerHasBlendMode(bool b) { m_childLayerHasBlendMode = b; } + + bool childLayerHasBlendModeStatusDirty() const { return m_childLayerHasBlendModeStatusDirty; } + void setChildLayerHasBlendModeStatusDirty(bool b) { m_childLayerHasBlendModeStatusDirty = b; } + + void setAncestorChainBlendedDescendant(); + void dirtyAncestorChainBlendedDescendantStatus(); + + blink::WebBlendMode blendMode() const { return m_blendMode; } + +private: + RenderLayerModelObject& m_renderer; + blink::WebBlendMode m_blendMode; + + unsigned m_childLayerHasBlendMode : 1; + unsigned m_childLayerHasBlendModeStatusDirty : 1; +}; + +} // namespace WebCore + +#endif // RenderLayerBlendInfo_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerClipper.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerClipper.cpp index f14aa06ee27..786a17f7440 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerClipper.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerClipper.cpp @@ -53,9 +53,12 @@ void RenderLayerClipper::updateClipRects(const ClipRectsContext& clipRectsContex { ClipRectsType clipRectsType = clipRectsContext.clipRectsType; ASSERT(clipRectsType < NumCachedClipRectsTypes); - if (m_clipRectsCache && m_clipRectsCache->getClipRects(clipRectsType, clipRectsContext.respectOverflowClip)) { - // FIXME: these asserts trigger for squashing. Need to update this code to support squashing as appropriate. - ASSERT(clipRectsContext.rootLayer == m_clipRectsCache->m_clipRectsRoot[clipRectsType]); + if (m_clipRectsCache + && clipRectsContext.rootLayer == m_clipRectsCache->clipRectsRoot(clipRectsType) + && m_clipRectsCache->getClipRects(clipRectsType, clipRectsContext.respectOverflowClip)) { + // FIXME: We used to ASSERT that we always got a consistent root layer. + // We should add a test that has an inconsistent root. See + // http://crbug.com/366118 for an example. ASSERT(m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] == clipRectsContext.overlayScrollbarSizeRelevancy); #ifdef CHECK_CACHED_CLIP_RECTS @@ -71,7 +74,7 @@ void RenderLayerClipper::updateClipRects(const ClipRectsContext& clipRectsContex // For transformed layers, the root layer was shifted to be us, so there is no need to // examine the parent. We want to cache clip rects with us as the root. - RenderLayer* parentLayer = clipRectsContext.rootLayer != m_renderer->layer() ? m_renderer->layer()->parent() : 0; + RenderLayer* parentLayer = !isClippingRootForContext(clipRectsContext) ? m_renderer.layer()->parent() : 0; if (parentLayer) parentLayer->clipper().updateClipRects(clipRectsContext); @@ -82,12 +85,11 @@ void RenderLayerClipper::updateClipRects(const ClipRectsContext& clipRectsContex m_clipRectsCache = adoptPtr(new ClipRectsCache); if (parentLayer && parentLayer->clipper().clipRects(clipRectsContext) && clipRects == *parentLayer->clipper().clipRects(clipRectsContext)) - m_clipRectsCache->setClipRects(clipRectsType, clipRectsContext.respectOverflowClip, parentLayer->clipper().clipRects(clipRectsContext)); + m_clipRectsCache->setClipRects(clipRectsType, clipRectsContext.respectOverflowClip, parentLayer->clipper().clipRects(clipRectsContext), clipRectsContext.rootLayer); else - m_clipRectsCache->setClipRects(clipRectsType, clipRectsContext.respectOverflowClip, ClipRects::create(clipRects)); + m_clipRectsCache->setClipRects(clipRectsType, clipRectsContext.respectOverflowClip, ClipRects::create(clipRects), clipRectsContext.rootLayer); #ifndef NDEBUG - m_clipRectsCache->m_clipRectsRoot[clipRectsType] = clipRectsContext.rootLayer; m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] = clipRectsContext.overlayScrollbarSizeRelevancy; #endif } @@ -100,7 +102,7 @@ void RenderLayerClipper::clearClipRectsIncludingDescendants(ClipRectsType typeTo clearClipRects(typeToClear); - for (RenderLayer* layer = m_renderer->layer()->firstChild(); layer; layer = layer->nextSibling()) + for (RenderLayer* layer = m_renderer.layer()->firstChild(); layer; layer = layer->nextSibling()) layer->clipper().clearClipRectsIncludingDescendants(typeToClear); } @@ -108,17 +110,118 @@ void RenderLayerClipper::clearClipRects(ClipRectsType typeToClear) { if (typeToClear == AllClipRectTypes) { m_clipRectsCache = nullptr; + m_compositingClipRectsDirty = false; } else { + if (typeToClear == CompositingClipRects) + m_compositingClipRectsDirty = false; + ASSERT(typeToClear < NumCachedClipRectsTypes); RefPtr<ClipRects> dummy; - m_clipRectsCache->setClipRects(typeToClear, RespectOverflowClip, dummy); - m_clipRectsCache->setClipRects(typeToClear, IgnoreOverflowClip, dummy); + m_clipRectsCache->setClipRects(typeToClear, RespectOverflowClip, dummy, 0); + m_clipRectsCache->setClipRects(typeToClear, IgnoreOverflowClip, dummy, 0); + } +} + +LayoutRect RenderLayerClipper::childrenClipRect() const +{ + // FIXME: border-radius not accounted for. + // FIXME: Regions not accounted for. + RenderView* renderView = m_renderer.view(); + RenderLayer* clippingRootLayer = clippingRootForPainting(); + LayoutRect layerBounds; + ClipRect backgroundRect, foregroundRect, outlineRect; + ClipRectsContext clipRectsContext(clippingRootLayer, TemporaryClipRects); + // Need to use temporary clip rects, because the value of 'dontClipToOverflow' may be different from the painting path (<rdar://problem/11844909>). + calculateRects(clipRectsContext, renderView->unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); + return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregroundRect.rect())).enclosingBoundingBox(); +} + +LayoutRect RenderLayerClipper::localClipRect() const +{ + // FIXME: border-radius not accounted for. + RenderLayer* clippingRootLayer = clippingRootForPainting(); + LayoutRect layerBounds; + ClipRect backgroundRect, foregroundRect, outlineRect; + ClipRectsContext clipRectsContext(clippingRootLayer, PaintingClipRects); + calculateRects(clipRectsContext, PaintInfo::infiniteRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); + + LayoutRect clipRect = backgroundRect.rect(); + if (clipRect == PaintInfo::infiniteRect()) + return clipRect; + + LayoutPoint clippingRootOffset; + m_renderer.layer()->convertToLayerCoords(clippingRootLayer, clippingRootOffset); + clipRect.moveBy(-clippingRootOffset); + + return clipRect; +} + +void RenderLayerClipper::calculateRects(const ClipRectsContext& clipRectsContext, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, + ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, const LayoutPoint* offsetFromRoot) const +{ + bool isClippingRoot = isClippingRootForContext(clipRectsContext); + + if (!isClippingRoot && m_renderer.layer()->parent()) { + backgroundRect = backgroundClipRect(clipRectsContext); + backgroundRect.move(roundedIntSize(clipRectsContext.subPixelAccumulation)); + backgroundRect.intersect(paintDirtyRect); + } else { + backgroundRect = paintDirtyRect; + } + + foregroundRect = backgroundRect; + outlineRect = backgroundRect; + + LayoutPoint offset; + if (offsetFromRoot) + offset = *offsetFromRoot; + else + m_renderer.layer()->convertToLayerCoords(clipRectsContext.rootLayer, offset); + layerBounds = LayoutRect(offset, m_renderer.layer()->size()); + + // Update the clip rects that will be passed to child layers. + if (m_renderer.hasOverflowClip()) { + // This layer establishes a clip of some kind. + if (!isClippingRoot || clipRectsContext.respectOverflowClip == RespectOverflowClip) { + foregroundRect.intersect(toRenderBox(m_renderer).overflowClipRect(offset, clipRectsContext.overlayScrollbarSizeRelevancy)); + if (m_renderer.style()->hasBorderRadius()) + foregroundRect.setHasRadius(true); + } + + // If we establish an overflow clip at all, then go ahead and make sure our background + // rect is intersected with our layer's bounds including our visual overflow, + // since any visual overflow like box-shadow or border-outset is not clipped by overflow:auto/hidden. + if (toRenderBox(m_renderer).hasVisualOverflow()) { + // FIXME: Perhaps we should be propagating the borderbox as the clip rect for children, even though + // we may need to inflate our clip specifically for shadows or outsets. + // FIXME: Does not do the right thing with CSS regions yet, since we don't yet factor in the + // individual region boxes as overflow. + LayoutRect layerBoundsWithVisualOverflow = toRenderBox(m_renderer).visualOverflowRect(); + toRenderBox(m_renderer).flipForWritingMode(layerBoundsWithVisualOverflow); // Layers are in physical coordinates, so the overflow has to be flipped. + layerBoundsWithVisualOverflow.moveBy(offset); + if (!isClippingRoot || clipRectsContext.respectOverflowClip == RespectOverflowClip) + backgroundRect.intersect(layerBoundsWithVisualOverflow); + } else { + LayoutRect bounds = toRenderBox(m_renderer).borderBoxRect(); + bounds.moveBy(offset); + if (!isClippingRoot || clipRectsContext.respectOverflowClip == RespectOverflowClip) + backgroundRect.intersect(bounds); + } + } + + // CSS clip (different than clipping due to overflow) can clip to any box, even if it falls outside of the border box. + if (m_renderer.hasClip()) { + // Clip applies to *us* as well, so go ahead and update the damageRect. + LayoutRect newPosClip = toRenderBox(m_renderer).clipRect(offset); + backgroundRect.intersect(newPosClip); + foregroundRect.intersect(newPosClip); + outlineRect.intersect(newPosClip); } } void RenderLayerClipper::calculateClipRects(const ClipRectsContext& clipRectsContext, ClipRects& clipRects) const { - if (!m_renderer->layer()->parent()) { + if (!m_renderer.layer()->parent()) { // The root layer's clip rect is always infinite. clipRects.reset(PaintInfo::infiniteRect()); return; @@ -127,9 +230,11 @@ void RenderLayerClipper::calculateClipRects(const ClipRectsContext& clipRectsCon ClipRectsType clipRectsType = clipRectsContext.clipRectsType; bool useCached = clipRectsType != TemporaryClipRects; + bool isClippingRoot = isClippingRootForContext(clipRectsContext); + // For transformed layers, the root layer was shifted to be us, so there is no need to // examine the parent. We want to cache clip rects with us as the root. - RenderLayer* parentLayer = clipRectsContext.rootLayer != m_renderer->layer() ? m_renderer->layer()->parent() : 0; + RenderLayer* parentLayer = !isClippingRoot ? m_renderer.layer()->parent() : 0; // Ensure that our parent's clip has been calculated so that we can examine the values. if (parentLayer) { @@ -146,41 +251,41 @@ void RenderLayerClipper::calculateClipRects(const ClipRectsContext& clipRectsCon // A fixed object is essentially the root of its containing block hierarchy, so when // we encounter such an object, we reset our clip rects to the fixedClipRect. - if (m_renderer->style()->position() == FixedPosition) { + if (m_renderer.style()->position() == FixedPosition) { clipRects.setPosClipRect(clipRects.fixedClipRect()); clipRects.setOverflowClipRect(clipRects.fixedClipRect()); clipRects.setFixed(true); - } else if (m_renderer->style()->hasInFlowPosition()) { + } else if (m_renderer.style()->hasInFlowPosition()) { clipRects.setPosClipRect(clipRects.overflowClipRect()); - } else if (m_renderer->style()->position() == AbsolutePosition) { + } else if (m_renderer.style()->position() == AbsolutePosition) { clipRects.setOverflowClipRect(clipRects.posClipRect()); } // Update the clip rects that will be passed to child layers. - if ((m_renderer->hasOverflowClip() && (clipRectsContext.respectOverflowClip == RespectOverflowClip || m_renderer->layer() != clipRectsContext.rootLayer)) || m_renderer->hasClip()) { + if ((m_renderer.hasOverflowClip() && (clipRectsContext.respectOverflowClip == RespectOverflowClip || !isClippingRoot)) || m_renderer.hasClip()) { // This layer establishes a clip of some kind. // This offset cannot use convertToLayerCoords, because sometimes our rootLayer may be across // some transformed layer boundary, for example, in the RenderLayerCompositor overlapMap, where // clipRects are needed in view space. LayoutPoint offset; - offset = roundedLayoutPoint(m_renderer->localToContainerPoint(FloatPoint(), clipRectsContext.rootLayer->renderer())); - RenderView* view = m_renderer->view(); + offset = roundedLayoutPoint(m_renderer.localToContainerPoint(FloatPoint(), clipRectsContext.rootLayer->renderer())); + RenderView* view = m_renderer.view(); ASSERT(view); if (view && clipRects.fixed() && clipRectsContext.rootLayer->renderer() == view) { offset -= view->frameView()->scrollOffsetForFixedPosition(); } - if (m_renderer->hasOverflowClip()) { - ClipRect newOverflowClip = toRenderBox(m_renderer)->overflowClipRect(offset, clipRectsContext.region, clipRectsContext.overlayScrollbarSizeRelevancy); - if (m_renderer->style()->hasBorderRadius()) + if (m_renderer.hasOverflowClip()) { + ClipRect newOverflowClip = toRenderBox(m_renderer).overflowClipRect(offset, clipRectsContext.overlayScrollbarSizeRelevancy); + if (m_renderer.style()->hasBorderRadius()) newOverflowClip.setHasRadius(true); clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect())); - if (m_renderer->isPositioned()) + if (m_renderer.isPositioned()) clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect())); } - if (m_renderer->hasClip()) { - LayoutRect newPosClip = toRenderBox(m_renderer)->clipRect(offset, clipRectsContext.region); + if (m_renderer.hasClip()) { + LayoutRect newPosClip = toRenderBox(m_renderer).clipRect(offset); clipRects.setPosClipRect(intersection(newPosClip, clipRects.posClipRect())); clipRects.setOverflowClipRect(intersection(newPosClip, clipRects.overflowClipRect())); clipRects.setFixedClipRect(intersection(newPosClip, clipRects.fixedClipRect())); @@ -188,4 +293,95 @@ void RenderLayerClipper::calculateClipRects(const ClipRectsContext& clipRectsCon } } +static inline ClipRect backgroundClipRectForPosition(const ClipRects& parentRects, EPosition position) +{ + if (position == FixedPosition) + return parentRects.fixedClipRect(); + + if (position == AbsolutePosition) + return parentRects.posClipRect(); + + return parentRects.overflowClipRect(); +} + +void RenderLayerClipper::setCompositingClipRectsDirty() +{ + m_compositingClipRectsDirty = true; +} + +ClipRect RenderLayerClipper::backgroundClipRect(const ClipRectsContext& clipRectsContext) const +{ + ASSERT(m_renderer.layer()->parent()); + + if (clipRectsContext.clipRectsType == CompositingClipRects) + const_cast<RenderLayerClipper*>(this)->clearClipRectsIncludingDescendants(CompositingClipRects); + + ClipRects parentRects; + + // If we cross into a different pagination context, then we can't rely on the cache. + // Just switch over to using TemporaryClipRects. + if (clipRectsContext.clipRectsType != TemporaryClipRects && m_renderer.layer()->parent()->enclosingPaginationLayer() != m_renderer.layer()->enclosingPaginationLayer()) { + ClipRectsContext tempContext(clipRectsContext); + tempContext.clipRectsType = TemporaryClipRects; + parentClipRects(tempContext, parentRects); + } else { + parentClipRects(clipRectsContext, parentRects); + } + + ClipRect backgroundClipRect = backgroundClipRectForPosition(parentRects, m_renderer.style()->position()); + RenderView* view = m_renderer.view(); + ASSERT(view); + + // Note: infinite clipRects should not be scrolled here, otherwise they will accidentally no longer be considered infinite. + if (parentRects.fixed() && clipRectsContext.rootLayer->renderer() == view && backgroundClipRect != PaintInfo::infiniteRect()) + backgroundClipRect.move(view->frameView()->scrollOffsetForFixedPosition()); + + return backgroundClipRect; +} + +bool RenderLayerClipper::isClippingRootForContext(const ClipRectsContext& clipRectsContext) const +{ + return clipRectsContext.rootLayer == m_renderer.layer(); +} + +void RenderLayerClipper::parentClipRects(const ClipRectsContext& clipRectsContext, ClipRects& clipRects) const +{ + // The root is not clipped. + if (isClippingRootForContext(clipRectsContext)) { + clipRects.reset(PaintInfo::infiniteRect()); + return; + } + + ASSERT(m_renderer.layer()->parent()); + + RenderLayerClipper& parentClipper = m_renderer.layer()->parent()->clipper(); + if (clipRectsContext.clipRectsType == TemporaryClipRects) { + parentClipper.calculateClipRects(clipRectsContext, clipRects); + return; + } + + parentClipper.updateClipRects(clipRectsContext); + clipRects = *parentClipper.clipRects(clipRectsContext); +} + +RenderLayer* RenderLayerClipper::clippingRootForPainting() const +{ + if (m_renderer.hasCompositedLayerMapping() || m_renderer.groupedMapping()) + return const_cast<RenderLayer*>(m_renderer.layer()); + + const RenderLayer* current = m_renderer.layer(); + while (current) { + if (current->isRootLayer()) + return const_cast<RenderLayer*>(current); + + current = current->compositingContainer(); + ASSERT(current); + if (current->transform() || (current->compositingState() == PaintsIntoOwnBacking) || current->groupedMapping()) + return const_cast<RenderLayer*>(current); + } + + ASSERT_NOT_REACHED(); + return 0; +} + } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerClipper.h b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerClipper.h index 03a3ef1a603..362097929ff 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerClipper.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerClipper.h @@ -51,28 +51,28 @@ namespace WebCore { class RenderLayer; -class RenderRegion; struct ClipRectsContext { - ClipRectsContext(const RenderLayer* inRootLayer, RenderRegion* inRegion, ClipRectsType inClipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, ShouldRespectOverflowClip inRespectOverflowClip = RespectOverflowClip) + ClipRectsContext(const RenderLayer* inRootLayer, ClipRectsType inClipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, ShouldRespectOverflowClip inRespectOverflowClip = RespectOverflowClip, const LayoutSize& inSubPixelAccumulation = LayoutSize()) : rootLayer(inRootLayer) - , region(inRegion) , clipRectsType(inClipRectsType) , overlayScrollbarSizeRelevancy(inOverlayScrollbarSizeRelevancy) , respectOverflowClip(inRespectOverflowClip) + , subPixelAccumulation(inSubPixelAccumulation) { } const RenderLayer* rootLayer; - RenderRegion* region; ClipRectsType clipRectsType; OverlayScrollbarSizeRelevancy overlayScrollbarSizeRelevancy; ShouldRespectOverflowClip respectOverflowClip; + LayoutSize subPixelAccumulation; }; -class RenderLayerClipper { +class RenderLayerClipper FINAL { WTF_MAKE_NONCOPYABLE(RenderLayerClipper); public: - RenderLayerClipper(RenderLayerModelObject* renderer) - : m_renderer(renderer) + explicit RenderLayerClipper(RenderLayerModelObject& renderer) + : m_renderer(renderer) + , m_compositingClipRectsDirty(false) { } @@ -88,15 +88,38 @@ public: void clearClipRectsIncludingDescendants(ClipRectsType typeToClear = AllClipRectTypes); void clearClipRects(ClipRectsType typeToClear = AllClipRectTypes); + void setCompositingClipRectsDirty(); + + LayoutRect childrenClipRect() const; // Returns the foreground 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. + + ClipRect backgroundClipRect(const ClipRectsContext&) const; + + // FIXME: The following functions should be private. + + // This method figures out our layerBounds in coordinates relative to + // |rootLayer}. It also computes our background and foreground clip rects + // for painting/event handling. + // Pass offsetFromRoot if known. + void calculateRects(const ClipRectsContext&, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, + ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, const LayoutPoint* offsetFromRoot = 0) const; + // Compute and return the clip rects. If useCached is true, will used previously computed clip rects on ancestors // (rather than computing them all from scratch up the parent chain). void calculateClipRects(const ClipRectsContext&, ClipRects&) const; private: - // FIXME: Could this be a RenderBox? - RenderLayerModelObject* m_renderer; + void parentClipRects(const ClipRectsContext&, ClipRects&) const; + + // The layer relative to which clipping rects for this layer are computed. + RenderLayer* clippingRootForPainting() const; + bool isClippingRootForContext(const ClipRectsContext&) const; + + // FIXME: Could this be a RenderBox? + RenderLayerModelObject& m_renderer; OwnPtr<ClipRectsCache> m_clipRectsCache; + unsigned m_compositingClipRectsDirty : 1; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerCompositor.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerCompositor.cpp deleted file mode 100644 index 45565a55007..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerCompositor.cpp +++ /dev/null @@ -1,2605 +0,0 @@ -/* - * Copyright (C) 2009, 2010 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 "core/rendering/RenderLayerCompositor.h" - -#include "CSSPropertyNames.h" -#include "HTMLNames.h" -#include "RuntimeEnabledFeatures.h" -#include "core/animation/ActiveAnimations.h" -#include "core/animation/DocumentAnimations.h" -#include "core/dom/FullscreenElementStack.h" -#include "core/dom/NodeList.h" -#include "core/html/HTMLCanvasElement.h" -#include "core/html/HTMLIFrameElement.h" -#include "core/html/HTMLVideoElement.h" -#include "core/html/canvas/CanvasRenderingContext.h" -#include "core/inspector/InspectorInstrumentation.h" -#include "core/page/Chrome.h" -#include "core/frame/Frame.h" -#include "core/frame/FrameView.h" -#include "core/page/Page.h" -#include "core/frame/Settings.h" -#include "core/frame/animation/AnimationController.h" -#include "core/page/scrolling/ScrollingConstraints.h" -#include "core/page/scrolling/ScrollingCoordinator.h" -#include "core/rendering/CompositedLayerMapping.h" -#include "core/rendering/HitTestResult.h" -#include "core/rendering/RenderApplet.h" -#include "core/rendering/RenderEmbeddedObject.h" -#include "core/rendering/RenderFullScreen.h" -#include "core/rendering/RenderGeometryMap.h" -#include "core/rendering/RenderIFrame.h" -#include "core/rendering/RenderLayerStackingNode.h" -#include "core/rendering/RenderLayerStackingNodeIterator.h" -#include "core/rendering/RenderReplica.h" -#include "core/rendering/RenderVideo.h" -#include "core/rendering/RenderView.h" -#include "platform/OverscrollTheme.h" -#include "platform/TraceEvent.h" -#include "platform/geometry/TransformState.h" -#include "platform/graphics/GraphicsLayer.h" -#include "platform/scroll/ScrollbarTheme.h" -#include "public/platform/Platform.h" -#include "wtf/TemporaryChange.h" - -#ifndef NDEBUG -#include "core/rendering/RenderTreeAsText.h" -#endif - -namespace WebCore { - -using namespace HTMLNames; - -class OverlapMapContainer { -public: - void add(const IntRect& bounds) - { - m_layerRects.append(bounds); - m_boundingBox.unite(bounds); - } - - bool overlapsLayers(const IntRect& bounds) const - { - // Checking with the bounding box will quickly reject cases when - // layers are created for lists of items going in one direction and - // never overlap with each other. - if (!bounds.intersects(m_boundingBox)) - return false; - for (unsigned i = 0; i < m_layerRects.size(); i++) { - if (m_layerRects[i].intersects(bounds)) - return true; - } - return false; - } - - void unite(const OverlapMapContainer& otherContainer) - { - m_layerRects.append(otherContainer.m_layerRects); - m_boundingBox.unite(otherContainer.m_boundingBox); - } -private: - Vector<IntRect> m_layerRects; - IntRect m_boundingBox; -}; - -class RenderLayerCompositor::OverlapMap { - WTF_MAKE_NONCOPYABLE(OverlapMap); -public: - OverlapMap() - : m_geometryMap(UseTransforms) - { - // Begin by assuming the root layer will be composited so that there - // is something on the stack. The root layer should also never get a - // finishCurrentOverlapTestingContext() call. - beginNewOverlapTestingContext(); - } - - void add(const RenderLayer* layer, const IntRect& bounds) - { - // Layers do not contribute to overlap immediately--instead, they will - // contribute to overlap as soon as they have been recursively processed - // and popped off the stack. - ASSERT(m_overlapStack.size() >= 2); - m_overlapStack[m_overlapStack.size() - 2].add(bounds); - m_layers.add(layer); - } - - bool contains(const RenderLayer* layer) - { - return m_layers.contains(layer); - } - - bool overlapsLayers(const IntRect& bounds) const - { - return m_overlapStack.last().overlapsLayers(bounds); - } - - bool isEmpty() - { - return m_layers.isEmpty(); - } - - void beginNewOverlapTestingContext() - { - // This effectively creates a new "clean slate" for overlap state. - // This is used when we know that a subtree or remaining set of - // siblings does not need to check overlap with things behind it. - m_overlapStack.append(OverlapMapContainer()); - } - - void finishCurrentOverlapTestingContext() - { - // The overlap information on the top of the stack is still necessary - // for checking overlap of any layers outside this context that may - // overlap things from inside this context. Therefore, we must merge - // the information from the top of the stack before popping the stack. - // - // FIXME: we may be able to avoid this deep copy by rearranging how - // overlapMap state is managed. - m_overlapStack[m_overlapStack.size() - 2].unite(m_overlapStack.last()); - m_overlapStack.removeLast(); - } - - RenderGeometryMap& geometryMap() { return m_geometryMap; } - -private: - Vector<OverlapMapContainer> m_overlapStack; - HashSet<const RenderLayer*> m_layers; - RenderGeometryMap m_geometryMap; -}; - -struct CompositingRecursionData { - CompositingRecursionData(RenderLayer* compAncestor, bool testOverlap) - : m_compositingAncestor(compAncestor) - , m_subtreeIsCompositing(false) - , m_hasUnisolatedCompositedBlendingDescendant(false) - , m_testingOverlap(testOverlap) -#ifndef NDEBUG - , m_depth(0) -#endif - { - } - - CompositingRecursionData(const CompositingRecursionData& other) - : m_compositingAncestor(other.m_compositingAncestor) - , m_subtreeIsCompositing(other.m_subtreeIsCompositing) - , m_hasUnisolatedCompositedBlendingDescendant(other.m_hasUnisolatedCompositedBlendingDescendant) - , m_testingOverlap(other.m_testingOverlap) -#ifndef NDEBUG - , m_depth(other.m_depth + 1) -#endif - { - } - - RenderLayer* m_compositingAncestor; - bool m_subtreeIsCompositing; - bool m_hasUnisolatedCompositedBlendingDescendant; - bool m_testingOverlap; -#ifndef NDEBUG - int m_depth; -#endif -}; - - -RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView) - : m_renderView(renderView) - , m_hasAcceleratedCompositing(true) - , m_compositingTriggers(static_cast<ChromeClient::CompositingTriggerFlags>(ChromeClient::AllTriggers)) - , m_showRepaintCounter(false) - , m_needsToRecomputeCompositingRequirements(false) - , m_needsToUpdateLayerTreeGeometry(false) - , m_compositing(false) - , m_compositingLayersNeedRebuild(false) - , m_forceCompositingMode(false) - , m_inPostLayoutUpdate(false) - , m_needsUpdateCompositingRequirementsState(false) - , m_isTrackingRepaints(false) - , m_rootLayerAttachment(RootLayerUnattached) -{ -} - -RenderLayerCompositor::~RenderLayerCompositor() -{ - ASSERT(m_rootLayerAttachment == RootLayerUnattached); -} - -void RenderLayerCompositor::enableCompositingMode(bool enable /* = true */) -{ - if (enable != m_compositing) { - m_compositing = enable; - - if (m_compositing) { - ensureRootLayer(); - notifyIFramesOfCompositingChange(); - } else - destroyRootLayer(); - } -} - -void RenderLayerCompositor::cacheAcceleratedCompositingFlags() -{ - bool hasAcceleratedCompositing = false; - bool showRepaintCounter = false; - bool forceCompositingMode = false; - - if (Settings* settings = m_renderView->document().settings()) { - hasAcceleratedCompositing = settings->acceleratedCompositingEnabled(); - - // We allow the chrome to override the settings, in case the page is rendered - // on a chrome that doesn't allow accelerated compositing. - if (hasAcceleratedCompositing) { - if (Page* page = this->page()) { - m_compositingTriggers = page->chrome().client().allowedCompositingTriggers(); - hasAcceleratedCompositing = m_compositingTriggers; - } - } - - showRepaintCounter = settings->showRepaintCounter(); - forceCompositingMode = settings->forceCompositingMode() && hasAcceleratedCompositing; - - if (forceCompositingMode && !isMainFrame()) - forceCompositingMode = requiresCompositingForScrollableFrame(); - } - - if (hasAcceleratedCompositing != m_hasAcceleratedCompositing || showRepaintCounter != m_showRepaintCounter || forceCompositingMode != m_forceCompositingMode) - setCompositingLayersNeedRebuild(); - - m_hasAcceleratedCompositing = hasAcceleratedCompositing; - m_showRepaintCounter = showRepaintCounter; - m_forceCompositingMode = forceCompositingMode; -} - -bool RenderLayerCompositor::layerSquashingEnabled() const -{ - if (Settings* settings = m_renderView->document().settings()) - return settings->layerSquashingEnabled(); - - return false; -} - -bool RenderLayerCompositor::canRender3DTransforms() const -{ - return hasAcceleratedCompositing() && (m_compositingTriggers & ChromeClient::ThreeDTransformTrigger); -} - -void RenderLayerCompositor::setCompositingLayersNeedRebuild(bool needRebuild) -{ - // FIXME: crbug,com/332248 ideally this could be merged with setNeedsCompositingUpdate(). - if (inCompositingMode()) - m_compositingLayersNeedRebuild = needRebuild; - - m_renderView->frameView()->scheduleAnimation(); -} - -void RenderLayerCompositor::didChangeVisibleRect() -{ - GraphicsLayer* rootLayer = rootGraphicsLayer(); - if (!rootLayer) - return; - - FrameView* frameView = m_renderView ? m_renderView->frameView() : 0; - if (!frameView) - return; - - IntRect visibleRect = m_containerLayer ? IntRect(IntPoint(), frameView->contentsSize()) : frameView->visibleContentRect(); - if (rootLayer->visibleRectChangeRequiresFlush(visibleRect)) { - if (Page* page = this->page()) - page->chrome().client().scheduleCompositingLayerFlush(); - } -} - -void RenderLayerCompositor::updateCompositingRequirementsState() -{ - if (!m_needsUpdateCompositingRequirementsState) - return; - - TRACE_EVENT0("blink_rendering,comp-scroll", "RenderLayerCompositor::updateCompositingRequirementsState"); - - m_needsUpdateCompositingRequirementsState = false; - - if (!rootRenderLayer() || !rootRenderLayer()->acceleratedCompositingForOverflowScrollEnabled()) - return; - - for (HashSet<RenderLayer*>::iterator it = m_outOfFlowPositionedLayers.begin(); it != m_outOfFlowPositionedLayers.end(); ++it) - (*it)->updateHasUnclippedDescendant(); - - const FrameView::ScrollableAreaSet* scrollableAreas = m_renderView->frameView()->scrollableAreas(); - if (!scrollableAreas) - return; - - for (FrameView::ScrollableAreaSet::iterator it = scrollableAreas->begin(); it != scrollableAreas->end(); ++it) - (*it)->updateNeedsCompositedScrolling(); -} - -static RenderVideo* findFullscreenVideoRenderer(Document* document) -{ - Element* fullscreenElement = FullscreenElementStack::currentFullScreenElementFrom(document); - while (fullscreenElement && fullscreenElement->isFrameOwnerElement()) { - document = toHTMLFrameOwnerElement(fullscreenElement)->contentDocument(); - if (!document) - return 0; - fullscreenElement = FullscreenElementStack::currentFullScreenElementFrom(document); - } - if (!fullscreenElement || !isHTMLVideoElement(fullscreenElement)) - return 0; - RenderObject* renderer = fullscreenElement->renderer(); - if (!renderer) - return 0; - return toRenderVideo(renderer); -} - -void RenderLayerCompositor::finishCompositingUpdateForFrameTree(Frame* frame) -{ - for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling()) - finishCompositingUpdateForFrameTree(child); - - // Update compositing for current frame after all descendant frames are updated. - if (frame && frame->contentRenderer()) { - RenderLayerCompositor* frameCompositor = frame->contentRenderer()->compositor(); - if (frameCompositor && !frameCompositor->isMainFrame()) - frame->contentRenderer()->compositor()->updateCompositingLayers(CompositingUpdateFinishAllDeferredWork); - } -} - -void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType updateType) -{ - // Avoid updating the layers with old values. Compositing layers will be updated after the layout is finished. - if (m_renderView->needsLayout()) - return; - - if (updateType == CompositingUpdateFinishAllDeferredWork && isMainFrame() && m_renderView->frameView()) - finishCompositingUpdateForFrameTree(&m_renderView->frameView()->frame()); - - if (m_forceCompositingMode && !m_compositing) - enableCompositingMode(true); - - if (!m_needsToRecomputeCompositingRequirements && !m_compositing) - return; - - AnimationUpdateBlock animationUpdateBlock(m_renderView->frameView()->frame().animation()); - - TemporaryChange<bool> postLayoutChange(m_inPostLayoutUpdate, true); - - bool needCompositingRequirementsUpdate = false; - bool needHierarchyAndGeometryUpdate = false; - bool needGeometryUpdate = false; - bool needsToUpdateScrollingCoordinator = false; - - // CompositingUpdateFinishAllDeferredWork is the only updateType that will actually do any work in this - // function. All other updateTypes will simply mark that something needed updating, and defer the actual - // update. This way we only need to compute all compositing state once for every frame drawn (if needed). - switch (updateType) { - case CompositingUpdateAfterStyleChange: - case CompositingUpdateAfterLayout: - m_needsToRecomputeCompositingRequirements = true; - break; - case CompositingUpdateOnScroll: - m_needsToRecomputeCompositingRequirements = true; // Overlap can change with scrolling, so need to check for hierarchy updates. - m_needsToUpdateLayerTreeGeometry = true; - break; - case CompositingUpdateOnCompositedScroll: - m_needsToUpdateLayerTreeGeometry = true; - break; - case CompositingUpdateFinishAllDeferredWork: - needCompositingRequirementsUpdate = m_needsToRecomputeCompositingRequirements; - needHierarchyAndGeometryUpdate = m_compositingLayersNeedRebuild; - needGeometryUpdate = m_needsToUpdateLayerTreeGeometry; - needsToUpdateScrollingCoordinator = scrollingCoordinator() ? scrollingCoordinator()->needsToUpdateAfterCompositingChange() : false; - break; - } - - if (!needCompositingRequirementsUpdate && !needHierarchyAndGeometryUpdate && !needGeometryUpdate && !needsToUpdateScrollingCoordinator) - return; - - ASSERT(updateType == CompositingUpdateFinishAllDeferredWork); - - // Only clear the flags if we're updating the entire hierarchy. - m_compositingLayersNeedRebuild = false; - m_needsToUpdateLayerTreeGeometry = false; - m_needsToRecomputeCompositingRequirements = false; - RenderLayer* updateRoot = rootRenderLayer(); - - if (needCompositingRequirementsUpdate) { - // 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. - CompositingRecursionData recursionData(updateRoot, true); - bool layersChanged = false; - bool saw3DTransform = false; - { - TRACE_EVENT0("blink_rendering", "RenderLayerCompositor::computeCompositingRequirements"); - OverlapMap overlapTestRequestMap; - - // FIXME: Passing these unclippedDescendants down and keeping track - // of them dynamically, we are requiring a full tree walk. This - // should be removed as soon as proper overlap testing based on - // scrolling and animation bounds is implemented (crbug.com/252472). - Vector<RenderLayer*> unclippedDescendants; - computeCompositingRequirements(0, updateRoot, &overlapTestRequestMap, recursionData, saw3DTransform, unclippedDescendants); - } - - { - TRACE_EVENT0("blink_rendering", "RenderLayerCompositor::assignLayersToBackings"); - assignLayersToBackings(updateRoot, layersChanged); - } - - { - TRACE_EVENT0("blink_rendering", "RenderLayerCompositor::updateHasVisibleNonLayerContentLoop"); - const FrameView::ScrollableAreaSet* scrollableAreas = m_renderView->frameView()->scrollableAreas(); - if (scrollableAreas) { - for (FrameView::ScrollableAreaSet::iterator it = scrollableAreas->begin(); it != scrollableAreas->end(); ++it) - (*it)->updateHasVisibleNonLayerContent(); - } - } - - needHierarchyAndGeometryUpdate |= layersChanged; - } - - if (needHierarchyAndGeometryUpdate) { - // Update the hierarchy of the compositing layers. - Vector<GraphicsLayer*> childList; - { - TRACE_EVENT0("blink_rendering", "RenderLayerCompositor::rebuildCompositingLayerTree"); - rebuildCompositingLayerTree(updateRoot, childList, 0); - } - - // Host the document layer in the RenderView's root layer. - if (RuntimeEnabledFeatures::overlayFullscreenVideoEnabled() && isMainFrame()) { - RenderVideo* video = findFullscreenVideoRenderer(&m_renderView->document()); - if (video && video->hasCompositedLayerMapping()) { - childList.clear(); - childList.append(video->compositedLayerMapping()->mainGraphicsLayer()); - } - } - - if (childList.isEmpty()) - destroyRootLayer(); - else - m_rootContentLayer->setChildren(childList); - } 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); - } - - ASSERT(updateRoot || !m_compositingLayersNeedRebuild); - - if (!hasAcceleratedCompositing()) - enableCompositingMode(false); - - // The scrolling coordinator may realize that it needs updating while compositing was being updated in this function. - needsToUpdateScrollingCoordinator |= scrollingCoordinator() ? scrollingCoordinator()->needsToUpdateAfterCompositingChange() : false; - if (needsToUpdateScrollingCoordinator && isMainFrame() && scrollingCoordinator() && inCompositingMode()) - scrollingCoordinator()->updateAfterCompositingChange(); - - // Inform the inspector that the layer tree has changed. - if (isMainFrame()) - InspectorInstrumentation::layerTreeDidChange(page()); -} - -static bool requiresCompositing(CompositingReasons reasons) -{ - // Any reasons other than overlap or assumed overlap will require the layer to be separately compositing. - return reasons & ~CompositingReasonComboAllOverlapReasons; -} - -static bool requiresSquashing(CompositingReasons reasons) -{ - // If the layer has overlap or assumed overlap, but no other reasons, then it should be squashed. - return !requiresCompositing(reasons) && (reasons & CompositingReasonComboAllOverlapReasons); -} - -static bool requiresCompositingOrSquashing(CompositingReasons reasons) -{ -#ifndef NDEBUG - bool fastAnswer = reasons != CompositingReasonNone; - bool slowAnswer = requiresCompositing(reasons) || requiresSquashing(reasons); - ASSERT(fastAnswer == slowAnswer); -#endif - return reasons != CompositingReasonNone; -} - -void RenderLayerCompositor::addOutOfFlowPositionedLayer(RenderLayer* layer) -{ - m_outOfFlowPositionedLayers.add(layer); -} - -void RenderLayerCompositor::removeOutOfFlowPositionedLayer(RenderLayer* layer) -{ - m_outOfFlowPositionedLayers.remove(layer); -} - -bool RenderLayerCompositor::allocateOrClearCompositedLayerMapping(RenderLayer* layer) -{ - bool compositedLayerMappingChanged = false; - RenderLayer::ViewportConstrainedNotCompositedReason viewportConstrainedNotCompositedReason = RenderLayer::NoNotCompositedReason; - requiresCompositingForPosition(layer->renderer(), layer, &viewportConstrainedNotCompositedReason); - - // FIXME: It would be nice to directly use the layer's compositing reason, - // but allocateOrClearCompositedLayerMapping also gets called without having updated compositing - // requirements fully. - if (needsOwnBacking(layer)) { - enableCompositingMode(); - - if (!layer->hasCompositedLayerMapping()) { - // If we need to repaint, do so before allocating the compositedLayerMapping - repaintOnCompositingChange(layer); - - layer->ensureCompositedLayerMapping(); - compositedLayerMappingChanged = true; - - // At this time, the ScrollingCooridnator only supports the top-level frame. - if (layer->isRootLayer() && isMainFrame()) { - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->frameViewRootLayerDidChange(m_renderView->frameView()); - } - - // If this layer was previously squashed, we need to remove its reference to a groupedMapping right away, so - // that computing repaint rects will know the layer's correct compositingState. - // FIXME: do we need to also remove the layer from it's location in the squashing list of its groupedMapping? - // Need to create a test where a squashed layer pops into compositing. And also to cover all other - // sorts of compositingState transitions. - layer->setGroupedMapping(0); - - // FIXME: it seems premature to compute this before all compositing state has been updated? - // This layer and all of its descendants have cached repaints rects that are relative to - // the repaint container, so change when compositing changes; we need to update them here. - if (layer->parent()) - layer->repainter().computeRepaintRectsIncludingDescendants(); - } - - if (layer->compositedLayerMapping()->updateRequiresOwnBackingStoreForIntrinsicReasons()) - compositedLayerMappingChanged = true; - } else { - if (layer->hasCompositedLayerMapping()) { - // If we're removing the compositedLayerMapping from a reflection, clear the source GraphicsLayer's pointer to - // its replica GraphicsLayer. In practice this should never happen because reflectee and reflection - // are both either composited, or not composited. - if (layer->isReflection()) { - RenderLayer* sourceLayer = toRenderLayerModelObject(layer->renderer()->parent())->layer(); - if (sourceLayer->hasCompositedLayerMapping()) { - ASSERT(sourceLayer->compositedLayerMapping()->mainGraphicsLayer()->replicaLayer() == layer->compositedLayerMapping()->mainGraphicsLayer()); - sourceLayer->compositedLayerMapping()->mainGraphicsLayer()->setReplicatedByLayer(0); - } - } - - removeViewportConstrainedLayer(layer); - - layer->clearCompositedLayerMapping(); - compositedLayerMappingChanged = true; - - // This layer and all of its descendants have cached repaints rects that are relative to - // the repaint container, so change when compositing changes; we need to update them here. - layer->repainter().computeRepaintRectsIncludingDescendants(); - - // If we need to repaint, do so now that we've removed the compositedLayerMapping - repaintOnCompositingChange(layer); - } - } - - if (compositedLayerMappingChanged && layer->renderer()->isRenderPart()) { - RenderLayerCompositor* innerCompositor = frameContentsCompositor(toRenderPart(layer->renderer())); - if (innerCompositor && innerCompositor->inCompositingMode()) - innerCompositor->updateRootLayerAttachment(); - } - - if (compositedLayerMappingChanged) - layer->clipper().clearClipRectsIncludingDescendants(PaintingClipRects); - - // If a fixed position layer gained/lost a compositedLayerMapping or the reason not compositing it changed, - // the scrolling coordinator needs to recalculate whether it can do fast scrolling. - bool nonCompositedReasonChanged = false; - if (layer->renderer()->style()->position() == FixedPosition) { - if (layer->viewportConstrainedNotCompositedReason() != viewportConstrainedNotCompositedReason) { - layer->setViewportConstrainedNotCompositedReason(viewportConstrainedNotCompositedReason); - nonCompositedReasonChanged = true; - } - if (compositedLayerMappingChanged || nonCompositedReasonChanged) { - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->frameViewFixedObjectsDidChange(m_renderView->frameView()); - } - } - - return compositedLayerMappingChanged || nonCompositedReasonChanged; -} - -bool RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer) -{ - updateDirectCompositingReasons(layer); - bool layerChanged = allocateOrClearCompositedLayerMapping(layer); - - if (layerSquashingEnabled()) { - // FIXME: this is not correct... info may be out of date and squashing returning true doesn't indicate that the layer changed - layerChanged = requiresSquashing(layer->compositingReasons()); - } - - // See if we need content or clipping layers. Methods called here should assume - // that the compositing state of descendant layers has not been updated yet. - if (layer->hasCompositedLayerMapping() && layer->compositedLayerMapping()->updateGraphicsLayerConfiguration()) - layerChanged = true; - - return layerChanged; -} - -void RenderLayerCompositor::repaintOnCompositingChange(RenderLayer* layer) -{ - // If the renderer is not attached yet, no need to repaint. - if (layer->renderer() != m_renderView && !layer->renderer()->parent()) - return; - - RenderLayerModelObject* repaintContainer = layer->renderer()->containerForRepaint(); - if (!repaintContainer) - repaintContainer = m_renderView; - - layer->repainter().repaintIncludingNonCompositingDescendants(repaintContainer); -} - -// This method assumes that layout is up-to-date, unlike repaintOnCompositingChange(). -void RenderLayerCompositor::repaintInCompositedAncestor(RenderLayer* layer, const LayoutRect& rect) -{ - RenderLayer* compositedAncestor = layer->enclosingCompositingLayerForRepaint(false /*exclude self*/); - if (compositedAncestor) { - // FIXME: make sure repaintRect is computed correctly for squashed scenario - LayoutPoint offset; - layer->convertToLayerCoords(compositedAncestor, offset); - - LayoutRect repaintRect = rect; - repaintRect.moveBy(offset); - - if (compositedAncestor->compositingState() == PaintsIntoOwnBacking) { - compositedAncestor->repainter().setBackingNeedsRepaintInRect(repaintRect); - } else if (compositedAncestor->compositingState() == PaintsIntoGroupedBacking) { - // FIXME: Need to perform the correct coordinate conversion for repaintRect here, including transforms - compositedAncestor->groupedMapping()->squashingLayer()->setNeedsDisplayInRect(repaintRect); - } else { - ASSERT_NOT_REACHED(); - } - } -} - -// The bounds of the GraphicsLayer created for a compositing layer is the union of the bounds of all the descendant -// RenderLayers that are rendered by the composited RenderLayer. -IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer) const -{ - if (!canBeComposited(layer)) - return IntRect(); - - RenderLayer::CalculateLayerBoundsFlags flags = RenderLayer::DefaultCalculateLayerBoundsFlags | RenderLayer::ExcludeHiddenDescendants | RenderLayer::DontConstrainForMask; -#if HAVE(COMPOSITOR_FILTER_OUTSETS) - // If the compositor computes its own filter outsets, don't include them in the composited bounds. - if (!layer->paintsWithFilters()) - flags &= ~RenderLayer::IncludeLayerFilterOutsets; -#endif - return layer->calculateLayerBounds(ancestorLayer, 0, flags); -} - -void RenderLayerCompositor::layerWasAdded(RenderLayer* /*parent*/, RenderLayer* /*child*/) -{ - setCompositingLayersNeedRebuild(); -} - -void RenderLayerCompositor::layerWillBeRemoved(RenderLayer* parent, RenderLayer* child) -{ - if (!child->hasCompositedLayerMapping() || parent->renderer()->documentBeingDestroyed()) - return; - - removeViewportConstrainedLayer(child); - repaintInCompositedAncestor(child, child->compositedLayerMapping()->compositedBounds()); - - setCompositingParent(child, 0); - setCompositingLayersNeedRebuild(); -} - -RenderLayer* RenderLayerCompositor::enclosingNonStackingClippingLayer(const RenderLayer* layer) const -{ - for (RenderLayer* curr = layer->parent(); curr != 0; curr = curr->parent()) { - if (curr->stackingNode()->isStackingContainer()) - return 0; - - if (curr->renderer()->hasClipOrOverflowClip()) - return curr; - } - return 0; -} - -void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer* layer, IntRect& layerBounds, bool& boundsComputed) -{ - if (layer->isRootLayer()) - return; - - if (!boundsComputed) { - // FIXME: If this layer's overlap bounds include its children, we don't need to add its - // children's bounds to the overlap map. - layerBounds = enclosingIntRect(overlapMap.geometryMap().absoluteRect(layer->overlapBounds())); - // 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; - } - - IntRect clipRect = pixelSnappedIntRect(layer->backgroundClipRect(ClipRectsContext(rootRenderLayer(), 0, AbsoluteClipRects)).rect()); // FIXME: Incorrect for CSS regions. - clipRect.intersect(layerBounds); - overlapMap.add(layer, clipRect); -} - -void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, RenderLayer* layer, RenderLayer* ancestorLayer) -{ - if (!canBeComposited(layer) || overlapMap.contains(layer)) - return; - - // A null ancestorLayer is an indication that 'layer' has already been pushed. - if (ancestorLayer) - overlapMap.geometryMap().pushMappingsToAncestor(layer, ancestorLayer); - - IntRect bounds; - bool haveComputedBounds = false; - addToOverlapMap(overlapMap, layer, bounds, haveComputedBounds); - -#if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(layer->stackingNode()); -#endif - - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), AllChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) - addToOverlapMapRecursive(overlapMap, curNode->layer(), layer); - - if (ancestorLayer) - overlapMap.geometryMap().popMappingsToAncestor(ancestorLayer); -} - -// Recurse through the layers in z-index and overflow order (which is equivalent to painting order) -// For the z-order children of a compositing layer: -// If a child layers has a compositing layer, then all subsequent layers must -// be compositing in order to render above that layer. -// -// If a child in the negative z-order list is compositing, then the layer itself -// 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* ancestorLayer, RenderLayer* layer, OverlapMap* overlapMap, CompositingRecursionData& currentRecursionData, bool& descendantHas3DTransform, Vector<RenderLayer*>& unclippedDescendants) -{ - layer->stackingNode()->updateLayerListsIfNeeded(); - - if (overlapMap) - overlapMap->geometryMap().pushMappingsToAncestor(layer, ancestorLayer); - - // Clear the flag - layer->setHasCompositingDescendant(false); - layer->setHasNonCompositedChild(false); - - // Start by assuming this layer will not need to composite. - CompositingReasons reasonsToComposite = CompositingReasonNone; - - // First accumulate the straightforward compositing reasons. - CompositingReasons directReasons = directReasonsForCompositing(layer); - - // Video is special. It's the only RenderLayer type that can both have - // RenderLayer children and whose children can't use its backing to render - // into. These children (the controls) always need to be promoted into their - // own layers to draw on top of the accelerated video. - if (currentRecursionData.m_compositingAncestor && currentRecursionData.m_compositingAncestor->renderer()->isVideo()) - directReasons |= CompositingReasonLayerForVideoOverlay; - - if (canBeComposited(layer)) - reasonsToComposite |= directReasons; - - // Next, accumulate reasons related to overlap. - // If overlap testing is used, this reason will be overridden. If overlap testing is not - // used, we must assume we overlap if there is anything composited behind us in paint-order. - CompositingReasons overlapCompositingReason = currentRecursionData.m_subtreeIsCompositing ? CompositingReasonAssumedOverlap : CompositingReasonNone; - - if (rootRenderLayer()->compositorDrivenAcceleratedScrollingEnabled()) { - Vector<size_t> unclippedDescendantsToRemove; - for (size_t i = 0; i < unclippedDescendants.size(); i++) { - RenderLayer* unclippedDescendant = unclippedDescendants.at(i); - // If we've reached the containing block of one of the unclipped - // descendants, that element is no longer relevant to whether or not we - // should opt in. Unfortunately we can't easily remove from the list - // while we're iterating, so we have to store it for later removal. - if (unclippedDescendant->renderer()->containingBlock() == layer->renderer()) { - unclippedDescendantsToRemove.append(i); - continue; - } - if (layer->scrollsWithRespectTo(unclippedDescendant)) - reasonsToComposite |= CompositingReasonAssumedOverlap; - } - - // Remove irrelevant unclipped descendants in reverse order so our stored - // indices remain valid. - for (size_t i = 0; i < unclippedDescendantsToRemove.size(); i++) - unclippedDescendants.remove(unclippedDescendantsToRemove.at(unclippedDescendantsToRemove.size() - i - 1)); - - if (reasonsToComposite & CompositingReasonOutOfFlowClipping) - unclippedDescendants.append(layer); - } - - bool haveComputedBounds = false; - IntRect absBounds; - // If we know for sure the layer is going to be composited, don't bother looking it up in the overlap map. - if (overlapMap && !overlapMap->isEmpty() && currentRecursionData.m_testingOverlap && !requiresCompositingOrSquashing(directReasons)) { - // If we're testing for overlap, we only need to composite if we overlap something that is already composited. - absBounds = enclosingIntRect(overlapMap->geometryMap().absoluteRect(layer->overlapBounds())); - - // 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; - overlapCompositingReason = overlapMap->overlapsLayers(absBounds) ? CompositingReasonOverlap : CompositingReasonNone; - } - - reasonsToComposite |= overlapCompositingReason; - - // 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. - CompositingRecursionData childRecursionData(currentRecursionData); - childRecursionData.m_subtreeIsCompositing = false; - - bool willBeComposited = canBeComposited(layer) && requiresCompositingOrSquashing(reasonsToComposite); - if (willBeComposited) { - // Tell the parent it has compositing descendants. - currentRecursionData.m_subtreeIsCompositing = true; - // This layer now acts as the ancestor for kids. - childRecursionData.m_compositingAncestor = layer; - - // Here we know that all children and the layer's own contents can blindly paint into - // this layer's backing, until a descendant is composited. So, we don't need to check - // for overlap with anything behind this layer. - if (overlapMap) - overlapMap->beginNewOverlapTestingContext(); - // This layer is going to be composited, so children can safely ignore the fact that there's an - // animation running behind this layer, meaning they can rely on the overlap map testing again. - childRecursionData.m_testingOverlap = true; - } - -#if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(layer->stackingNode()); -#endif - - bool anyDescendantHas3DTransform = false; - bool willHaveForegroundLayer = false; - - if (layer->stackingNode()->isStackingContainer()) { - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NegativeZOrderChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) { - computeCompositingRequirements(layer, curNode->layer(), overlapMap, childRecursionData, anyDescendantHas3DTransform, unclippedDescendants); - - // If we have to make a layer for this child, make one now so we can have a contents layer - // (since we need to ensure that the -ve z-order child renders underneath our contents). - if (childRecursionData.m_subtreeIsCompositing) { - reasonsToComposite |= CompositingReasonNegativeZIndexChildren; - - if (!willBeComposited) { - // make layer compositing - childRecursionData.m_compositingAncestor = layer; - overlapMap->beginNewOverlapTestingContext(); - willBeComposited = true; - willHaveForegroundLayer = true; - - // FIXME: temporary solution for the first negative z-index composited child: - // re-compute the absBounds for the child so that we can add the - // negative z-index child's bounds to the new overlap context. - if (overlapMap) { - overlapMap->geometryMap().pushMappingsToAncestor(curNode->layer(), layer); - IntRect childAbsBounds = enclosingIntRect(overlapMap->geometryMap().absoluteRect(curNode->layer()->overlapBounds())); - bool boundsComputed = true; - overlapMap->beginNewOverlapTestingContext(); - addToOverlapMap(*overlapMap, curNode->layer(), childAbsBounds, boundsComputed); - overlapMap->finishCurrentOverlapTestingContext(); - overlapMap->geometryMap().popMappingsToAncestor(layer); - } - } - } - } - } - - if (overlapMap && willHaveForegroundLayer) { - ASSERT(willBeComposited); - // A foreground layer effectively is a new backing for all subsequent children, so - // we don't need to test for overlap with anything behind this. So, we can finish - // the previous context that was accumulating rects for the negative z-index - // children, and start with a fresh new empty context. - overlapMap->finishCurrentOverlapTestingContext(); - overlapMap->beginNewOverlapTestingContext(); - // This layer is going to be composited, so children can safely ignore the fact that there's an - // animation running behind this layer, meaning they can rely on the overlap map testing again - childRecursionData.m_testingOverlap = true; - } - - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) - computeCompositingRequirements(layer, curNode->layer(), overlapMap, childRecursionData, anyDescendantHas3DTransform, unclippedDescendants); - - // Now that the subtree has been traversed, we can check for compositing reasons that depended on the state of the subtree. - - // If we entered compositing mode during the recursion, the root will also need to be composited (as long as accelerated compositing is enabled). - if (layer->isRootLayer()) { - if (inCompositingMode() && m_hasAcceleratedCompositing) - willBeComposited = true; - } - - // All layers (even ones that aren't being composited) need to get added to - // the overlap map. Layers that are not separately composited will paint into their - // compositing ancestor's backing, and so are still considered for overlap. - if (overlapMap && childRecursionData.m_compositingAncestor && !childRecursionData.m_compositingAncestor->isRootLayer()) - addToOverlapMap(*overlapMap, layer, absBounds, haveComputedBounds); - - if (layer->stackingNode()->isStackingContext()) { - layer->setShouldIsolateCompositedDescendants(childRecursionData.m_hasUnisolatedCompositedBlendingDescendant); - } else { - layer->setShouldIsolateCompositedDescendants(false); - currentRecursionData.m_hasUnisolatedCompositedBlendingDescendant = childRecursionData.m_hasUnisolatedCompositedBlendingDescendant; - } - - // Now check for reasons to become composited that depend on the state of descendant layers. - CompositingReasons subtreeCompositingReasons = subtreeReasonsForCompositing(layer->renderer(), childRecursionData.m_subtreeIsCompositing, anyDescendantHas3DTransform); - reasonsToComposite |= subtreeCompositingReasons; - if (!willBeComposited && canBeComposited(layer) && requiresCompositingOrSquashing(subtreeCompositingReasons)) { - childRecursionData.m_compositingAncestor = layer; - if (overlapMap) { - // FIXME: this context push is effectively a no-op but needs to exist for - // now, because the code is designed to push overlap information to the - // second-from-top context of the stack. - overlapMap->beginNewOverlapTestingContext(); - addToOverlapMapRecursive(*overlapMap, layer); - } - willBeComposited = true; - } - - // If the original layer is composited, the reflection needs to be, too. - if (layer->reflectionInfo()) { - // FIXME: Shouldn't we call computeCompositingRequirements to handle a reflection overlapping with another renderer? - CompositingReasons reflectionCompositingReason = willBeComposited ? CompositingReasonReflectionOfCompositedParent : CompositingReasonNone; - layer->reflectionInfo()->reflectionLayer()->setCompositingReasons(layer->reflectionInfo()->reflectionLayer()->compositingReasons() | reflectionCompositingReason); - } - - // Subsequent layers in the parent's stacking context may also need to composite. - if (childRecursionData.m_subtreeIsCompositing) - currentRecursionData.m_subtreeIsCompositing = true; - - if (willBeComposited && layer->hasBlendMode()) - currentRecursionData.m_hasUnisolatedCompositedBlendingDescendant = true; - - // Set the flag to say that this SC has compositing children. - layer->setHasCompositingDescendant(childRecursionData.m_subtreeIsCompositing); - - // Turn overlap testing off for later layers if it's already off, or if we have an animating transform. - // Note that if the layer clips its descendants, there's no reason to propagate the child animation to the parent layers. That's because - // we know for sure the animation is contained inside the clipping rectangle, which is already added to the overlap map. - bool isCompositedClippingLayer = canBeComposited(layer) && (reasonsToComposite & CompositingReasonClipsCompositingDescendants); - if ((!childRecursionData.m_testingOverlap && !isCompositedClippingLayer) || isRunningAcceleratedTransformAnimation(layer->renderer())) - currentRecursionData.m_testingOverlap = false; - - if (overlapMap && childRecursionData.m_compositingAncestor == layer && !layer->isRootLayer()) - overlapMap->finishCurrentOverlapTestingContext(); - - if (layer->isRootLayer()) { - // The root layer needs to be composited if anything else in the tree is composited. - // Otherwise, we can disable compositing entirely. - if (childRecursionData.m_subtreeIsCompositing || requiresCompositingOrSquashing(reasonsToComposite) || m_forceCompositingMode) { - willBeComposited = true; - reasonsToComposite |= CompositingReasonRoot; - } else { - enableCompositingMode(false); - willBeComposited = false; - reasonsToComposite = CompositingReasonNone; - } - } - - // At this point we have finished collecting all reasons to composite this layer. - layer->setCompositingReasons(reasonsToComposite); - - if (!willBeComposited && layer->parent()) - layer->parent()->setHasNonCompositedChild(true); - - descendantHas3DTransform |= anyDescendantHas3DTransform || layer->has3DTransform(); - - if (overlapMap) - overlapMap->geometryMap().popMappingsToAncestor(ancestorLayer); -} - -void RenderLayerCompositor::SquashingState::updateSquashingStateForNewMapping(CompositedLayerMappingPtr newCompositedLayerMapping, bool hasNewCompositedLayerMapping, IntPoint newOffsetFromAbsolute) -{ - // The most recent backing is done accumulating any more squashing layers. - if (hasMostRecentMapping) - mostRecentMapping->finishAccumulatingSquashingLayers(nextSquashedLayerIndex); - - nextSquashedLayerIndex = 0; - mostRecentMapping = newCompositedLayerMapping; - hasMostRecentMapping = hasNewCompositedLayerMapping; - offsetFromAbsolute = newOffsetFromAbsolute; -} - -static IntPoint computeOffsetFromAbsolute(RenderLayer* layer) -{ - TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint()); - layer->renderer()->mapLocalToContainer(0, transformState, ApplyContainerFlip); - transformState.flatten(); - return roundedIntPoint(transformState.lastPlanarPoint()); -} - -void RenderLayerCompositor::assignLayersToBackings(RenderLayer* updateRoot, bool& layersChanged) -{ - SquashingState squashingState; - assignLayersToBackingsInternal(updateRoot, squashingState, layersChanged); - if (squashingState.hasMostRecentMapping) - squashingState.mostRecentMapping->finishAccumulatingSquashingLayers(squashingState.nextSquashedLayerIndex); -} - -void RenderLayerCompositor::assignLayersToBackingsInternal(RenderLayer* layer, SquashingState& squashingState, bool& layersChanged) -{ - if (allocateOrClearCompositedLayerMapping(layer)) - layersChanged = true; - - if (layer->reflectionInfo() && updateLayerCompositingState(layer->reflectionInfo()->reflectionLayer())) - layersChanged = true; - - // Add this layer to a squashing backing if needed. - if (layerSquashingEnabled()) { - // NOTE: In the future as we generalize this, the background of this layer may need to be assigned to a different backing than - // the layer's own primary contents. This would happen when we have a composited negative z-index element that needs to - // paint on top of the background, but below the layer's main contents. For now, because we always composite layers - // when they have a composited negative z-index child, such layers will never need squashing so it is not yet an issue. - if (requiresSquashing(layer->compositingReasons())) { - // A layer that is squashed with other layers cannot have its own CompositedLayerMapping. - ASSERT(!layer->hasCompositedLayerMapping()); - ASSERT(squashingState.hasMostRecentMapping); - - IntPoint offsetFromAbsolute = computeOffsetFromAbsolute(layer); - - // FIXME: see if we can refactor this to be clearer - IntSize offsetFromTargetBacking(offsetFromAbsolute.x() - squashingState.offsetFromAbsolute.x(), - offsetFromAbsolute.y() - squashingState.offsetFromAbsolute.y()); - - squashingState.mostRecentMapping->addRenderLayerToSquashingGraphicsLayer(layer, offsetFromTargetBacking, squashingState.nextSquashedLayerIndex); - squashingState.nextSquashedLayerIndex++; - - // FIXME: does this need to be true here? Do we need more logic to decide when it should be true? - layersChanged = true; - - // FIXME: this should be conditioned on whether this layer actually changed status - layer->clipper().clearClipRectsIncludingDescendants(); - } - } - - if (layer->stackingNode()->isStackingContainer()) { - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NegativeZOrderChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) - assignLayersToBackingsInternal(curNode->layer(), squashingState, layersChanged); - } - - if (layerSquashingEnabled()) { - // At this point, if the layer is to be "separately" composited, then its backing becomes the most recent in paint-order. - if (layer->compositingState() == PaintsIntoOwnBacking || layer->compositingState() == HasOwnBackingButPaintsIntoAncestor) { - ASSERT(!requiresSquashing(layer->compositingReasons())); - IntPoint offsetFromAbsolute = computeOffsetFromAbsolute(layer); - squashingState.updateSquashingStateForNewMapping(layer->compositedLayerMapping(), layer->hasCompositedLayerMapping(), offsetFromAbsolute); - } - } - - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) - assignLayersToBackingsInternal(curNode->layer(), squashingState, layersChanged); -} - -void RenderLayerCompositor::setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer) -{ - ASSERT(!parentLayer || childLayer->ancestorCompositingLayer() == parentLayer); - ASSERT(childLayer->hasCompositedLayerMapping()); - - // It's possible to be called with a parent that isn't yet composited when we're doing - // partial updates as required by painting or hit testing. Just bail in that case; - // we'll do a full layer update soon. - if (!parentLayer || !parentLayer->hasCompositedLayerMapping()) - return; - - if (parentLayer) { - GraphicsLayer* hostingLayer = parentLayer->compositedLayerMapping()->parentForSublayers(); - GraphicsLayer* hostedLayer = childLayer->compositedLayerMapping()->childForSuperlayers(); - - hostingLayer->addChild(hostedLayer); - } else { - childLayer->compositedLayerMapping()->childForSuperlayers()->removeFromParent(); - } -} - -void RenderLayerCompositor::removeCompositedChildren(RenderLayer* layer) -{ - ASSERT(layer->hasCompositedLayerMapping()); - - GraphicsLayer* hostingLayer = layer->compositedLayerMapping()->parentForSublayers(); - hostingLayer->removeAllChildren(); -} - -bool RenderLayerCompositor::canAccelerateVideoRendering(RenderVideo* o) const -{ - if (!m_hasAcceleratedCompositing) - return false; - - return o->supportsAcceleratedRendering(); -} - -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 - // have been processed. computeCompositingRequirements() will already have done the repaint if necessary. - - layer->stackingNode()->updateLayerListsIfNeeded(); - - // Used for gathering UMA data about the effect on memory usage of promoting all layers - // that have a webkit-transition on opacity or transform and intersect the viewport. - static double pixelsWithoutPromotingAllTransitions = 0.0; - static double pixelsAddedByPromotingAllTransitions = 0.0; - - if (!depth) { - pixelsWithoutPromotingAllTransitions = 0.0; - pixelsAddedByPromotingAllTransitions = 0.0; - } - - const bool hasCompositedLayerMapping = layer->hasCompositedLayerMapping(); - CompositedLayerMappingPtr currentCompositedLayerMapping = layer->compositedLayerMapping(); - if (hasCompositedLayerMapping) { - // The compositing state of all our children has been updated already, so now - // we can compute and cache the composited bounds for this layer. - currentCompositedLayerMapping->updateCompositedBounds(); - - if (layer->reflectionInfo()) { - RenderLayer* reflectionLayer = layer->reflectionInfo()->reflectionLayer(); - if (reflectionLayer->hasCompositedLayerMapping()) - reflectionLayer->compositedLayerMapping()->updateCompositedBounds(); - } - - currentCompositedLayerMapping->updateGraphicsLayerConfiguration(); - currentCompositedLayerMapping->updateGraphicsLayerGeometry(); - - if (!layer->parent()) - updateRootLayerPosition(); - - if (currentCompositedLayerMapping->hasUnpositionedOverflowControlsLayers()) - layer->scrollableArea()->positionOverflowControls(); - - pixelsWithoutPromotingAllTransitions += layer->size().height() * layer->size().width(); - } else { - if ((layer->renderer()->style()->transitionForProperty(CSSPropertyOpacity) || - layer->renderer()->style()->transitionForProperty(CSSPropertyWebkitTransform)) && - m_renderView->viewRect().intersects(layer->absoluteBoundingBox())) - pixelsAddedByPromotingAllTransitions += layer->size().height() * layer->size().width(); - } - - // If this layer has a compositedLayerMapping, then that is where we place subsequent children GraphicsLayers. - // Otherwise children continue to append to the child list of the enclosing layer. - Vector<GraphicsLayer*> layerChildren; - Vector<GraphicsLayer*>& childList = hasCompositedLayerMapping ? layerChildren : childLayersOfEnclosingLayer; - -#if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(layer->stackingNode()); -#endif - - if (layer->stackingNode()->isStackingContainer()) { - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NegativeZOrderChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) - rebuildCompositingLayerTree(curNode->layer(), childList, depth + 1); - - // If a negative z-order child is compositing, we get a foreground layer which needs to get parented. - if (hasCompositedLayerMapping && currentCompositedLayerMapping->foregroundLayer()) - childList.append(currentCompositedLayerMapping->foregroundLayer()); - } - - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) - rebuildCompositingLayerTree(curNode->layer(), childList, depth + 1); - - if (hasCompositedLayerMapping) { - bool parented = false; - if (layer->renderer()->isRenderPart()) - parented = parentFrameContentLayers(toRenderPart(layer->renderer())); - - if (!parented) - currentCompositedLayerMapping->parentForSublayers()->setChildren(layerChildren); - - // If the layer has a clipping layer the overflow controls layers will be siblings of the clipping layer. - // Otherwise, the overflow control layers are normal children. - if (!currentCompositedLayerMapping->hasClippingLayer() && !currentCompositedLayerMapping->hasScrollingLayer()) { - if (GraphicsLayer* overflowControlLayer = currentCompositedLayerMapping->layerForHorizontalScrollbar()) { - overflowControlLayer->removeFromParent(); - currentCompositedLayerMapping->parentForSublayers()->addChild(overflowControlLayer); - } - - if (GraphicsLayer* overflowControlLayer = currentCompositedLayerMapping->layerForVerticalScrollbar()) { - overflowControlLayer->removeFromParent(); - currentCompositedLayerMapping->parentForSublayers()->addChild(overflowControlLayer); - } - - if (GraphicsLayer* overflowControlLayer = currentCompositedLayerMapping->layerForScrollCorner()) { - overflowControlLayer->removeFromParent(); - currentCompositedLayerMapping->parentForSublayers()->addChild(overflowControlLayer); - } - } - - childLayersOfEnclosingLayer.append(currentCompositedLayerMapping->childForSuperlayers()); - } - - if (!depth) { - int percentageIncreaseInPixels = static_cast<int>(pixelsAddedByPromotingAllTransitions / pixelsWithoutPromotingAllTransitions * 100); - blink::Platform::current()->histogramCustomCounts("Renderer.PixelIncreaseFromTransitions", percentageIncreaseInPixels, 0, 1000, 50); - } -} - -void RenderLayerCompositor::frameViewDidChangeLocation(const IntPoint& contentsOffset) -{ - if (m_overflowControlsHostLayer) - m_overflowControlsHostLayer->setPosition(contentsOffset); -} - -void RenderLayerCompositor::frameViewDidChangeSize() -{ - if (m_containerLayer) { - FrameView* frameView = m_renderView->frameView(); - m_containerLayer->setSize(frameView->unscaledVisibleContentSize()); - - frameViewDidScroll(); - updateOverflowControlsLayers(); - } -} - -enum AcceleratedFixedRootBackgroundHistogramBuckets { - ScrolledMainFrameBucket = 0, - ScrolledMainFrameWithAcceleratedFixedRootBackground = 1, - ScrolledMainFrameWithUnacceleratedFixedRootBackground = 2, - AcceleratedFixedRootBackgroundHistogramMax = 3 -}; - -void RenderLayerCompositor::frameViewDidScroll() -{ - FrameView* frameView = m_renderView->frameView(); - IntPoint scrollPosition = frameView->scrollPosition(); - - if (!m_scrollLayer) - return; - - bool scrollingCoordinatorHandlesOffset = false; - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) { - if (Settings* settings = m_renderView->document().settings()) { - if (isMainFrame() || settings->compositedScrollingForFramesEnabled()) - scrollingCoordinatorHandlesOffset = scrollingCoordinator->scrollableAreaScrollLayerDidChange(frameView); - } - } - - // Scroll position = scroll minimum + scroll offset. Adjust the layer's - // position to handle whatever the scroll coordinator isn't handling. - // The minimum scroll position is non-zero for RTL pages with overflow. - if (scrollingCoordinatorHandlesOffset) - m_scrollLayer->setPosition(-frameView->minimumScrollPosition()); - else - m_scrollLayer->setPosition(-scrollPosition); - - - blink::Platform::current()->histogramEnumeration("Renderer.AcceleratedFixedRootBackground", - ScrolledMainFrameBucket, - AcceleratedFixedRootBackgroundHistogramMax); - - if (!m_renderView->rootBackgroundIsEntirelyFixed()) - return; - - blink::Platform::current()->histogramEnumeration("Renderer.AcceleratedFixedRootBackground", - !!fixedRootBackgroundLayer() - ? ScrolledMainFrameWithAcceleratedFixedRootBackground - : ScrolledMainFrameWithUnacceleratedFixedRootBackground, - AcceleratedFixedRootBackgroundHistogramMax); -} - -void RenderLayerCompositor::frameViewDidLayout() -{ -} - -void RenderLayerCompositor::frameViewScrollbarsExistenceDidChange() -{ - if (m_containerLayer) - updateOverflowControlsLayers(); -} - -void RenderLayerCompositor::rootFixedBackgroundsChanged() -{ - if (!supportsFixedRootBackgroundCompositing()) - return; - - // To avoid having to make the fixed root background layer fixed positioned to - // stay put, we position it in the layer tree as follows: - // - // + Overflow controls host - // + Frame clip - // + (Fixed root background) <-- Here. - // + Frame scroll - // + Root content layer - // + Scrollbars - // - // That is, it needs to be the first child of the frame clip, the sibling of - // the frame scroll layer. The compositor does not own the background layer, it - // just positions it (like the foreground layer). - if (GraphicsLayer* backgroundLayer = fixedRootBackgroundLayer()) - m_containerLayer->addChildBelow(backgroundLayer, m_scrollLayer.get()); -} - -bool RenderLayerCompositor::scrollingLayerDidChange(RenderLayer* layer) -{ - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - return scrollingCoordinator->scrollableAreaScrollLayerDidChange(layer->scrollableArea()); - return false; -} - -String RenderLayerCompositor::layerTreeAsText(LayerTreeFlags flags) -{ - // Before dumping the layer tree, finish any pending compositing update. - updateCompositingLayers(CompositingUpdateFinishAllDeferredWork); - - if (!m_rootContentLayer) - return String(); - - // We skip dumping the scroll and clip layers to keep layerTreeAsText output - // similar between platforms (unless we explicitly request dumping from the - // root. - GraphicsLayer* rootLayer = m_rootContentLayer.get(); - if (flags & LayerTreeIncludesRootLayer) - rootLayer = rootGraphicsLayer(); - - String layerTreeText = rootLayer->layerTreeAsText(flags); - - // The true root layer is not included in the dump, so if we want to report - // its repaint rects, they must be included here. - if (flags & LayerTreeIncludesRepaintRects) - return m_renderView->frameView()->trackedRepaintRectsAsText() + layerTreeText; - - return layerTreeText; -} - -RenderLayerCompositor* RenderLayerCompositor::frameContentsCompositor(RenderPart* renderer) -{ - if (!renderer->node()->isFrameOwnerElement()) - return 0; - - HTMLFrameOwnerElement* element = toHTMLFrameOwnerElement(renderer->node()); - if (Document* contentDocument = element->contentDocument()) { - if (RenderView* view = contentDocument->renderView()) - return view->compositor(); - } - return 0; -} - -bool RenderLayerCompositor::parentFrameContentLayers(RenderPart* renderer) -{ - RenderLayerCompositor* innerCompositor = frameContentsCompositor(renderer); - if (!innerCompositor || !innerCompositor->inCompositingMode() || innerCompositor->rootLayerAttachment() != RootLayerAttachedViaEnclosingFrame) - return false; - - RenderLayer* layer = renderer->layer(); - if (!layer->hasCompositedLayerMapping()) - return false; - - CompositedLayerMappingPtr compositedLayerMapping = layer->compositedLayerMapping(); - GraphicsLayer* hostingLayer = compositedLayerMapping->parentForSublayers(); - GraphicsLayer* rootLayer = innerCompositor->rootGraphicsLayer(); - if (hostingLayer->children().size() != 1 || hostingLayer->children()[0] != rootLayer) { - hostingLayer->removeAllChildren(); - hostingLayer->addChild(rootLayer); - } - return true; -} - -// This just updates layer geometry without changing the hierarchy. -void RenderLayerCompositor::updateLayerTreeGeometry(RenderLayer* layer) -{ - if (layer->hasCompositedLayerMapping()) { - CompositedLayerMappingPtr compositedLayerMapping = layer->compositedLayerMapping(); - // The compositing state of all our children has been updated already, so now - // we can compute and cache the composited bounds for this layer. - compositedLayerMapping->updateCompositedBounds(); - - if (layer->reflectionInfo()) { - RenderLayer* reflectionLayer = layer->reflectionInfo()->reflectionLayer(); - if (reflectionLayer->hasCompositedLayerMapping()) - reflectionLayer->compositedLayerMapping()->updateCompositedBounds(); - } - - compositedLayerMapping->updateGraphicsLayerConfiguration(); - compositedLayerMapping->updateGraphicsLayerGeometry(); - - if (!layer->parent()) - updateRootLayerPosition(); - } - -#if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(layer->stackingNode()); -#endif - - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), AllChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) - updateLayerTreeGeometry(curNode->layer()); -} - -// Recurs down the RenderLayer tree until its finds the compositing descendants of compositingAncestor and updates their geometry. -void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayerStackingNode* compositingAncestor, RenderLayer* layer, bool compositedChildrenOnly) -{ - if (layer->stackingNode() != compositingAncestor) { - if (layer->hasCompositedLayerMapping()) { - CompositedLayerMappingPtr compositedLayerMapping = layer->compositedLayerMapping(); - compositedLayerMapping->updateCompositedBounds(); - - if (layer->reflectionInfo()) { - RenderLayer* reflectionLayer = layer->reflectionInfo()->reflectionLayer(); - if (reflectionLayer->hasCompositedLayerMapping()) - reflectionLayer->compositedLayerMapping()->updateCompositedBounds(); - } - - compositedLayerMapping->updateGraphicsLayerGeometry(); - if (compositedChildrenOnly) - return; - } - } - - if (layer->reflectionInfo()) - updateCompositingDescendantGeometry(compositingAncestor, layer->reflectionInfo()->reflectionLayer(), compositedChildrenOnly); - - if (!layer->hasCompositingDescendant()) - return; - -#if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(layer->stackingNode()); -#endif - - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), AllChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) - updateCompositingDescendantGeometry(compositingAncestor, curNode->layer(), compositedChildrenOnly); -} - - -void RenderLayerCompositor::repaintCompositedLayers(const IntRect* absRect) -{ - recursiveRepaintLayer(rootRenderLayer(), absRect); -} - -void RenderLayerCompositor::recursiveRepaintLayer(RenderLayer* layer, const IntRect* rect) -{ - // FIXME: This method does not work correctly with transforms. - if (layer->compositingState() == PaintsIntoOwnBacking) { - if (rect) - layer->repainter().setBackingNeedsRepaintInRect(*rect); - else - layer->repainter().setBackingNeedsRepaint(); - } - -#if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(layer->stackingNode()); -#endif - - unsigned childrenToVisit = NormalFlowChildren; - if (layer->hasCompositingDescendant()) - childrenToVisit |= PositiveZOrderChildren | NegativeZOrderChildren; - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), childrenToVisit); - while (RenderLayerStackingNode* curNode = iterator.next()) { - if (rect) { - IntRect childRect(*rect); - curNode->layer()->convertToPixelSnappedLayerCoords(layer, childRect); - recursiveRepaintLayer(curNode->layer(), &childRect); - } else { - recursiveRepaintLayer(curNode->layer()); - } - } -} - -RenderLayer* RenderLayerCompositor::rootRenderLayer() const -{ - return m_renderView->layer(); -} - -GraphicsLayer* RenderLayerCompositor::rootGraphicsLayer() const -{ - if (m_overflowControlsHostLayer) - return m_overflowControlsHostLayer.get(); - return m_rootContentLayer.get(); -} - -GraphicsLayer* RenderLayerCompositor::scrollLayer() const -{ - return m_scrollLayer.get(); -} - -void RenderLayerCompositor::setIsInWindow(bool isInWindow) -{ - if (!inCompositingMode()) - return; - - if (isInWindow) { - if (m_rootLayerAttachment != RootLayerUnattached) - return; - - RootLayerAttachment attachment = isMainFrame() ? RootLayerAttachedViaChromeClient : RootLayerAttachedViaEnclosingFrame; - attachRootLayer(attachment); - } else { - if (m_rootLayerAttachment == RootLayerUnattached) - return; - - detachRootLayer(); - } -} - -void RenderLayerCompositor::clearMappingForRenderLayerIncludingDescendants(RenderLayer* layer) -{ - if (!layer) - return; - - if (layer->hasCompositedLayerMapping()) { - removeViewportConstrainedLayer(layer); - layer->clearCompositedLayerMapping(); - } - - for (RenderLayer* currLayer = layer->firstChild(); currLayer; currLayer = currLayer->nextSibling()) - clearMappingForRenderLayerIncludingDescendants(currLayer); -} - -void RenderLayerCompositor::clearMappingForAllRenderLayers() -{ - clearMappingForRenderLayerIncludingDescendants(m_renderView->layer()); -} - -void RenderLayerCompositor::updateRootLayerPosition() -{ - if (m_rootContentLayer) { - const IntRect& documentRect = m_renderView->documentRect(); - m_rootContentLayer->setSize(documentRect.size()); - m_rootContentLayer->setPosition(documentRect.location()); -#if USE(RUBBER_BANDING) - if (m_layerForOverhangShadow) - OverscrollTheme::theme()->updateOverhangShadowLayer(m_layerForOverhangShadow.get(), m_rootContentLayer.get()); -#endif - } - if (m_containerLayer) { - FrameView* frameView = m_renderView->frameView(); - m_containerLayer->setSize(frameView->unscaledVisibleContentSize()); - } -} - -bool RenderLayerCompositor::has3DContent() const -{ - return layerHas3DContent(rootRenderLayer()); -} - -void RenderLayerCompositor::updateDirectCompositingReasons(RenderLayer* layer) -{ - CompositingReasons layerReasons = layer->compositingReasons(); - - layerReasons &= ~CompositingReasonComboAllDirectReasons; - layerReasons |= directReasonsForCompositing(layer); - layer->setCompositingReasons(layerReasons); -} - -bool RenderLayerCompositor::needsOwnBacking(const RenderLayer* layer) const -{ - if (!canBeComposited(layer)) - return false; - - // If squashing is disabled, then layers that would have been squashed should just be separately composited. - bool needsOwnBackingForDisabledSquashing = !layerSquashingEnabled() && requiresSquashing(layer->compositingReasons()); - - return requiresCompositing(layer->compositingReasons()) || needsOwnBackingForDisabledSquashing || (inCompositingMode() && layer->isRootLayer()); -} - -bool RenderLayerCompositor::canBeComposited(const RenderLayer* layer) const -{ - // 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()->flowThreadState() == RenderObject::NotInsideFlowThread; -} - -CompositingReasons RenderLayerCompositor::directReasonsForCompositing(const RenderLayer* layer) const -{ - RenderObject* renderer = layer->renderer(); - CompositingReasons directReasons = CompositingReasonNone; - - if (requiresCompositingForTransform(renderer)) - directReasons |= CompositingReason3DTransform; - - // Only zero or one of the following conditions will be true for a given RenderLayer. - if (requiresCompositingForVideo(renderer)) - directReasons |= CompositingReasonVideo; - else if (requiresCompositingForCanvas(renderer)) - directReasons |= CompositingReasonCanvas; - else if (requiresCompositingForPlugin(renderer)) - directReasons |= CompositingReasonPlugin; - else if (requiresCompositingForFrame(renderer)) - directReasons |= CompositingReasonIFrame; - - if (requiresCompositingForBackfaceVisibilityHidden(renderer)) - directReasons |= CompositingReasonBackfaceVisibilityHidden; - - if (requiresCompositingForAnimation(renderer)) - directReasons |= CompositingReasonAnimation; - - if (requiresCompositingForTransition(renderer)) - directReasons |= CompositingReasonAnimation; - - if (requiresCompositingForFilters(renderer)) - directReasons |= CompositingReasonFilters; - - if (requiresCompositingForPosition(renderer, layer)) - directReasons |= renderer->style()->position() == FixedPosition ? CompositingReasonPositionFixed : CompositingReasonPositionSticky; - - if (requiresCompositingForOverflowScrolling(layer)) - directReasons |= CompositingReasonOverflowScrollingTouch; - - if (requiresCompositingForOverflowScrollingParent(layer)) - directReasons |= CompositingReasonOverflowScrollingParent; - - if (requiresCompositingForOutOfFlowClipping(layer)) - directReasons |= CompositingReasonOutOfFlowClipping; - - return directReasons; -} - -// 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. -// Thus, a RenderLayer can be clipped by a RenderLayer that is an ancestor in the renderer hierarchy, -// but a sibling in the z-order hierarchy. -bool RenderLayerCompositor::clippedByAncestor(const RenderLayer* layer) const -{ - if (!layer->hasCompositedLayerMapping() || !layer->parent()) - return false; - - // FIXME: need to double-check if semantics of ancestorCompositingLayer() work correctly here? - const RenderLayer* compositingAncestor = layer->ancestorCompositingLayer(); - if (!compositingAncestor) - return false; - - // If the compositingAncestor clips, that will be taken care of by clipsCompositingDescendants(), - // so we only care about clipping between its first child that is our ancestor (the computeClipRoot), - // and layer. - const RenderLayer* computeClipRoot = 0; - const RenderLayer* curr = layer; - while (curr) { - const RenderLayer* next = curr->parent(); - if (next == compositingAncestor) { - computeClipRoot = curr; - break; - } - curr = next; - } - - if (!computeClipRoot || computeClipRoot == layer) - return false; - - return layer->backgroundClipRect(ClipRectsContext(computeClipRoot, 0, TemporaryClipRects)).rect() != PaintInfo::infiniteRect(); // FIXME: Incorrect for CSS regions. -} - -// Return true if the given layer is a stacking context and has compositing child -// layers that it needs to clip. In this case we insert a clipping GraphicsLayer -// into the hierarchy between this layer and its children in the z-order hierarchy. -bool RenderLayerCompositor::clipsCompositingDescendants(const RenderLayer* layer) const -{ - return layer->hasCompositingDescendant() && layer->renderer()->hasClipOrOverflowClip(); -} - -bool RenderLayerCompositor::requiresCompositingForScrollableFrame() const -{ - // Need this done first to determine overflow. - ASSERT(!m_renderView->needsLayout()); - if (isMainFrame()) - return false; - - if (!(m_compositingTriggers & ChromeClient::ScrollableInnerFrameTrigger)) - return false; - - FrameView* frameView = m_renderView->frameView(); - return frameView->isScrollable(); -} - -bool RenderLayerCompositor::requiresCompositingForTransform(RenderObject* renderer) const -{ - if (!(m_compositingTriggers & ChromeClient::ThreeDTransformTrigger)) - return false; - - RenderStyle* style = renderer->style(); - // Note that we ask the renderer if it has a transform, because the style may have transforms, - // but the renderer may be an inline that doesn't suppport them. - return renderer->hasTransform() && style->transform().has3DOperation(); -} - -bool RenderLayerCompositor::requiresCompositingForVideo(RenderObject* renderer) const -{ - if (RuntimeEnabledFeatures::overlayFullscreenVideoEnabled() && renderer->isVideo()) { - HTMLMediaElement* media = toHTMLMediaElement(renderer->node()); - if (media->isFullscreen()) - return true; - } - - if (!(m_compositingTriggers & ChromeClient::VideoTrigger)) - return false; - - if (renderer->isVideo()) { - RenderVideo* video = toRenderVideo(renderer); - return video->shouldDisplayVideo() && canAccelerateVideoRendering(video); - } - return false; -} - -bool RenderLayerCompositor::requiresCompositingForCanvas(RenderObject* renderer) const -{ - if (!(m_compositingTriggers & ChromeClient::CanvasTrigger)) - return false; - - if (renderer->isCanvas()) { - HTMLCanvasElement* canvas = toHTMLCanvasElement(renderer->node()); - return canvas->renderingContext() && canvas->renderingContext()->isAccelerated(); - } - return false; -} - -bool RenderLayerCompositor::requiresCompositingForPlugin(RenderObject* renderer) const -{ - if (!(m_compositingTriggers & ChromeClient::PluginTrigger)) - return false; - - bool composite = renderer->isEmbeddedObject() && toRenderEmbeddedObject(renderer)->allowsAcceleratedCompositing(); - if (!composite) - return false; - - // FIXME: this seems bogus. If we don't know the layout position/size of the plugin yet, would't that be handled elsewhere? - m_needsToRecomputeCompositingRequirements = true; - - RenderWidget* pluginRenderer = toRenderWidget(renderer); - // If we can't reliably know the size of the plugin yet, don't change compositing state. - if (pluginRenderer->needsLayout()) - return pluginRenderer->hasLayer() && pluginRenderer->layer()->hasCompositedLayerMapping(); - - // Don't go into compositing mode if height or width are zero, or size is 1x1. - IntRect contentBox = pixelSnappedIntRect(pluginRenderer->contentBoxRect()); - return contentBox.height() * contentBox.width() > 1; -} - -bool RenderLayerCompositor::requiresCompositingForFrame(RenderObject* renderer) const -{ - if (!renderer->isRenderPart()) - return false; - - RenderPart* frameRenderer = toRenderPart(renderer); - - if (!frameRenderer->requiresAcceleratedCompositing()) - return false; - - if (frameRenderer->node() && frameRenderer->node()->isFrameOwnerElement() && toHTMLFrameOwnerElement(frameRenderer->node())->contentFrame() && toHTMLFrameOwnerElement(frameRenderer->node())->contentFrame()->remotePlatformLayer()) - return true; - - // FIXME: this seems bogus. If we don't know the layout position/size of the frame yet, wouldn't that be handled elsehwere? - m_needsToRecomputeCompositingRequirements = true; - - RenderLayerCompositor* innerCompositor = frameContentsCompositor(frameRenderer); - if (!innerCompositor) - return false; - - // If we can't reliably know the size of the iframe yet, don't change compositing state. - if (renderer->needsLayout()) - return frameRenderer->hasLayer() && frameRenderer->layer()->hasCompositedLayerMapping(); - - // Don't go into compositing mode if height or width are zero. - IntRect contentBox = pixelSnappedIntRect(frameRenderer->contentBoxRect()); - return contentBox.height() * contentBox.width() > 0; -} - -bool RenderLayerCompositor::requiresCompositingForBackfaceVisibilityHidden(RenderObject* renderer) const -{ - return canRender3DTransforms() && renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden; -} - -bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* renderer) const -{ - if (!(m_compositingTriggers & ChromeClient::AnimationTrigger)) - return false; - - if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled()) - return renderer->animation().isRunningAcceleratableAnimationOnRenderer(renderer); - - return shouldCompositeForActiveAnimations(*renderer); -} - -bool RenderLayerCompositor::requiresCompositingForTransition(RenderObject* renderer) const -{ - if (!(m_compositingTriggers & ChromeClient::AnimationTrigger)) - return false; - - if (Settings* settings = m_renderView->document().settings()) { - if (!settings->acceleratedCompositingForTransitionEnabled()) - return false; - } - - return renderer->style()->transitionForProperty(CSSPropertyOpacity) - || renderer->style()->transitionForProperty(CSSPropertyWebkitFilter) - || renderer->style()->transitionForProperty(CSSPropertyWebkitTransform); -} - -CompositingReasons RenderLayerCompositor::subtreeReasonsForCompositing(RenderObject* renderer, bool hasCompositedDescendants, bool has3DTransformedDescendants) const -{ - CompositingReasons subtreeReasons = CompositingReasonNone; - - // FIXME: this seems to be a potentially different layer than the layer for which this was called. May not be an error, but is very confusing. - RenderLayer* layer = toRenderBoxModelObject(renderer)->layer(); - - // When a layer has composited descendants, some effects, like 2d transforms, filters, masks etc must be implemented - // via compositing so that they also apply to those composited descdendants. - if (hasCompositedDescendants) { - if (layer->transform()) - subtreeReasons |= CompositingReasonTransformWithCompositedDescendants; - - if (layer->shouldIsolateCompositedDescendants()) { - ASSERT(layer->stackingNode()->isStackingContext()); - subtreeReasons |= CompositingReasonIsolateCompositedDescendants; - } - - // If the implementation of createsGroup changes, we need to be aware of that in this part of code. - ASSERT((renderer->isTransparent() || renderer->hasMask() || renderer->hasFilter() || renderer->hasBlendMode()) == renderer->createsGroup()); - if (renderer->isTransparent()) - subtreeReasons |= CompositingReasonOpacityWithCompositedDescendants; - if (renderer->hasMask()) - subtreeReasons |= CompositingReasonMaskWithCompositedDescendants; - if (renderer->hasFilter()) - subtreeReasons |= CompositingReasonFilterWithCompositedDescendants; - if (renderer->hasBlendMode()) - subtreeReasons |= CompositingReasonBlendingWithCompositedDescendants; - - if (renderer->hasReflection()) - subtreeReasons |= CompositingReasonReflectionWithCompositedDescendants; - - if (renderer->hasClipOrOverflowClip()) - subtreeReasons |= CompositingReasonClipsCompositingDescendants; - } - - - // A layer with preserve-3d or perspective only needs to be composited if there are descendant layers that - // will be affected by the preserve-3d or perspective. - if (has3DTransformedDescendants) { - if (renderer->style()->transformStyle3D() == TransformStyle3DPreserve3D) - subtreeReasons |= CompositingReasonPreserve3D; - - if (renderer->style()->hasPerspective()) - subtreeReasons |= CompositingReasonPerspective; - } - - return subtreeReasons; -} - -bool RenderLayerCompositor::requiresCompositingForFilters(RenderObject* renderer) const -{ - if (!(m_compositingTriggers & ChromeClient::FilterTrigger)) - return false; - - return renderer->hasFilter(); -} - -bool RenderLayerCompositor::requiresCompositingForOverflowScrollingParent(const RenderLayer* layer) const -{ - return !!layer->scrollParent(); -} - -bool RenderLayerCompositor::requiresCompositingForOutOfFlowClipping(const RenderLayer* layer) const -{ - return layer->compositorDrivenAcceleratedScrollingEnabled() && layer->isUnclippedDescendant(); -} - -bool RenderLayerCompositor::requiresCompositingForPosition(RenderObject* renderer, const RenderLayer* layer, RenderLayer::ViewportConstrainedNotCompositedReason* viewportConstrainedNotCompositedReason) const -{ - // position:fixed elements that create their own stacking context (e.g. have an explicit z-index, - // opacity, transform) can get their own composited layer. A stacking context is required otherwise - // z-index and clipping will be broken. - if (!renderer->isPositioned()) - return false; - - EPosition position = renderer->style()->position(); - bool isFixed = renderer->isOutOfFlowPositioned() && position == FixedPosition; - if (isFixed && !layer->stackingNode()->isStackingContainer()) - return false; - - bool isSticky = renderer->isInFlowPositioned() && position == StickyPosition; - if (!isFixed && !isSticky) - return false; - - // FIXME: acceleratedCompositingForFixedPositionEnabled should probably be renamed acceleratedCompositingForViewportConstrainedPositionEnabled(). - if (Settings* settings = m_renderView->document().settings()) { - if (!settings->acceleratedCompositingForFixedPositionEnabled()) - return false; - } - - if (isSticky) - return true; - - RenderObject* container = renderer->container(); - // If the renderer is not hooked up yet then we have to wait until it is. - if (!container) { - m_needsToRecomputeCompositingRequirements = true; - return false; - } - - // Don't promote fixed position elements that are descendants of a non-view container, e.g. transformed elements. - // They will stay fixed wrt the container rather than the enclosing frame. - if (container != m_renderView) { - if (viewportConstrainedNotCompositedReason) - *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForNonViewContainer; - return false; - } - - // If the fixed-position element does not have any scrollable ancestor between it and - // its container, then we do not need to spend compositor resources for it. Start by - // assuming we can opt-out (i.e. no scrollable ancestor), and refine the answer below. - bool hasScrollableAncestor = false; - - // The FrameView has the scrollbars associated with the top level viewport, so we have to - // check the FrameView in addition to the hierarchy of ancestors. - FrameView* frameView = m_renderView->frameView(); - if (frameView && frameView->isScrollable()) - hasScrollableAncestor = true; - - RenderLayer* ancestor = layer->parent(); - while (ancestor && !hasScrollableAncestor) { - if (frameView->containsScrollableArea(ancestor->scrollableArea())) - hasScrollableAncestor = true; - if (ancestor->renderer() == m_renderView) - break; - ancestor = ancestor->parent(); - } - - if (!hasScrollableAncestor) { - if (viewportConstrainedNotCompositedReason) - *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForUnscrollableAncestors; - return false; - } - - // Subsequent tests depend on layout. If we can't tell now, just keep things the way they are until layout is done. - if (!m_inPostLayoutUpdate) { - m_needsToRecomputeCompositingRequirements = true; - return layer->hasCompositedLayerMapping(); - } - - bool paintsContent = layer->isVisuallyNonEmpty() || layer->hasVisibleDescendant(); - if (!paintsContent) { - if (viewportConstrainedNotCompositedReason) - *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForNoVisibleContent; - return false; - } - - // Fixed position elements that are invisible in the current view don't get their own layer. - if (FrameView* frameView = m_renderView->frameView()) { - LayoutRect viewBounds = frameView->viewportConstrainedVisibleContentRect(); - LayoutRect layerBounds = layer->calculateLayerBounds(rootRenderLayer(), 0, - RenderLayer::DefaultCalculateLayerBoundsFlags - | RenderLayer::ExcludeHiddenDescendants - | RenderLayer::DontConstrainForMask - | RenderLayer::IncludeCompositedDescendants - | RenderLayer::PretendLayerHasOwnBacking); - if (!viewBounds.intersects(enclosingIntRect(layerBounds))) { - if (viewportConstrainedNotCompositedReason) { - *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForBoundsOutOfView; - m_needsToRecomputeCompositingRequirements = true; - } - return false; - } - } - - return true; -} - -bool RenderLayerCompositor::requiresCompositingForOverflowScrolling(const RenderLayer* layer) const -{ - return layer->needsCompositedScrolling(); -} - -bool RenderLayerCompositor::isRunningAcceleratedTransformAnimation(RenderObject* renderer) const -{ - if (!(m_compositingTriggers & ChromeClient::AnimationTrigger)) - return false; - if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled()) - return renderer->animation().isRunningAnimationOnRenderer(renderer, CSSPropertyWebkitTransform); - return hasActiveAnimations(*renderer, CSSPropertyWebkitTransform); -} - -// 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. -bool RenderLayerCompositor::needsContentsCompositingLayer(const RenderLayer* layer) const -{ - return layer->stackingNode()->hasNegativeZOrderList(); -} - -static void paintScrollbar(Scrollbar* scrollbar, GraphicsContext& context, const IntRect& clip) -{ - if (!scrollbar) - return; - - context.save(); - const IntRect& scrollbarRect = scrollbar->frameRect(); - context.translate(-scrollbarRect.x(), -scrollbarRect.y()); - IntRect transformedClip = clip; - transformedClip.moveBy(scrollbarRect.location()); - scrollbar->paint(&context, transformedClip); - context.restore(); -} - -void RenderLayerCompositor::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& context, GraphicsLayerPaintingPhase, const IntRect& clip) -{ - if (graphicsLayer == layerForHorizontalScrollbar()) - paintScrollbar(m_renderView->frameView()->horizontalScrollbar(), context, clip); - else if (graphicsLayer == layerForVerticalScrollbar()) - paintScrollbar(m_renderView->frameView()->verticalScrollbar(), context, clip); - else if (graphicsLayer == layerForScrollCorner()) { - const IntRect& scrollCorner = m_renderView->frameView()->scrollCornerRect(); - context.save(); - context.translate(-scrollCorner.x(), -scrollCorner.y()); - IntRect transformedClip = clip; - transformedClip.moveBy(scrollCorner.location()); - m_renderView->frameView()->paintScrollCorner(&context, transformedClip); - context.restore(); - } -} - -bool RenderLayerCompositor::supportsFixedRootBackgroundCompositing() const -{ - if (Settings* settings = m_renderView->document().settings()) { - if (settings->acceleratedCompositingForFixedRootBackgroundEnabled()) - return true; - } - return false; -} - -bool RenderLayerCompositor::needsFixedRootBackgroundLayer(const RenderLayer* layer) const -{ - if (layer != m_renderView->layer()) - return false; - - return supportsFixedRootBackgroundCompositing() && m_renderView->rootBackgroundIsEntirelyFixed(); -} - -GraphicsLayer* RenderLayerCompositor::fixedRootBackgroundLayer() const -{ - // Get the fixed root background from the RenderView layer's compositedLayerMapping. - RenderLayer* viewLayer = m_renderView->layer(); - if (!viewLayer) - return 0; - - if (viewLayer->compositingState() == PaintsIntoOwnBacking && viewLayer->compositedLayerMapping()->backgroundLayerPaintsFixedRootBackground()) - return viewLayer->compositedLayerMapping()->backgroundLayer(); - - return 0; -} - -static void resetTrackedRepaintRectsRecursive(GraphicsLayer* graphicsLayer) -{ - if (!graphicsLayer) - return; - - graphicsLayer->resetTrackedRepaints(); - - for (size_t i = 0; i < graphicsLayer->children().size(); ++i) - resetTrackedRepaintRectsRecursive(graphicsLayer->children()[i]); - - if (GraphicsLayer* replicaLayer = graphicsLayer->replicaLayer()) - resetTrackedRepaintRectsRecursive(replicaLayer); - - if (GraphicsLayer* maskLayer = graphicsLayer->maskLayer()) - resetTrackedRepaintRectsRecursive(maskLayer); - - if (GraphicsLayer* clippingMaskLayer = graphicsLayer->contentsClippingMaskLayer()) - resetTrackedRepaintRectsRecursive(clippingMaskLayer); -} - -void RenderLayerCompositor::resetTrackedRepaintRects() -{ - if (GraphicsLayer* rootLayer = rootGraphicsLayer()) - resetTrackedRepaintRectsRecursive(rootLayer); -} - -void RenderLayerCompositor::setTracksRepaints(bool tracksRepaints) -{ - updateCompositingLayers(CompositingUpdateFinishAllDeferredWork); - m_isTrackingRepaints = tracksRepaints; -} - -bool RenderLayerCompositor::isTrackingRepaints() const -{ - return m_isTrackingRepaints; -} - -void RenderLayerCompositor::didCommitChangesForLayer(const GraphicsLayer*) const -{ - // Nothing to do here yet. -} - -static bool shouldCompositeOverflowControls(FrameView* view) -{ - if (Page* page = view->frame().page()) { - if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) - if (scrollingCoordinator->coordinatesScrollingForFrameView(view)) - return true; - } - - return true; -} - -bool RenderLayerCompositor::requiresHorizontalScrollbarLayer() const -{ - FrameView* view = m_renderView->frameView(); - return shouldCompositeOverflowControls(view) && view->horizontalScrollbar(); -} - -bool RenderLayerCompositor::requiresVerticalScrollbarLayer() const -{ - FrameView* view = m_renderView->frameView(); - return shouldCompositeOverflowControls(view) && view->verticalScrollbar(); -} - -bool RenderLayerCompositor::requiresScrollCornerLayer() const -{ - FrameView* view = m_renderView->frameView(); - return shouldCompositeOverflowControls(view) && view->isScrollCornerVisible(); -} - -#if USE(RUBBER_BANDING) -bool RenderLayerCompositor::requiresOverhangLayers() const -{ - // We don't want a layer if this is a subframe. - if (!isMainFrame()) - return false; - - // We do want a layer if we have a scrolling coordinator and can scroll. - if (scrollingCoordinator() && m_renderView->frameView()->hasOpaqueBackground()) - return true; - - // Chromium always wants a layer. - return true; -} -#endif - -void RenderLayerCompositor::updateOverflowControlsLayers() -{ -#if USE(RUBBER_BANDING) - if (requiresOverhangLayers()) { - if (!m_layerForOverhangShadow) { - m_layerForOverhangShadow = GraphicsLayer::create(graphicsLayerFactory(), this); - OverscrollTheme::theme()->setUpOverhangShadowLayer(m_layerForOverhangShadow.get()); - OverscrollTheme::theme()->updateOverhangShadowLayer(m_layerForOverhangShadow.get(), m_rootContentLayer.get()); - m_scrollLayer->addChild(m_layerForOverhangShadow.get()); - } - } else { - if (m_layerForOverhangShadow) { - m_layerForOverhangShadow->removeFromParent(); - m_layerForOverhangShadow = nullptr; - } - } -#endif - - if (requiresHorizontalScrollbarLayer()) { - if (!m_layerForHorizontalScrollbar) { - m_layerForHorizontalScrollbar = GraphicsLayer::create(graphicsLayerFactory(), this); - m_overflowControlsHostLayer->addChild(m_layerForHorizontalScrollbar.get()); - - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), HorizontalScrollbar); - } - } else if (m_layerForHorizontalScrollbar) { - m_layerForHorizontalScrollbar->removeFromParent(); - m_layerForHorizontalScrollbar = nullptr; - - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), HorizontalScrollbar); - } - - if (requiresVerticalScrollbarLayer()) { - if (!m_layerForVerticalScrollbar) { - m_layerForVerticalScrollbar = GraphicsLayer::create(graphicsLayerFactory(), this); - m_overflowControlsHostLayer->addChild(m_layerForVerticalScrollbar.get()); - - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), VerticalScrollbar); - } - } else if (m_layerForVerticalScrollbar) { - m_layerForVerticalScrollbar->removeFromParent(); - m_layerForVerticalScrollbar = nullptr; - - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), VerticalScrollbar); - } - - if (requiresScrollCornerLayer()) { - if (!m_layerForScrollCorner) { - m_layerForScrollCorner = GraphicsLayer::create(graphicsLayerFactory(), this); - m_overflowControlsHostLayer->addChild(m_layerForScrollCorner.get()); - } - } else if (m_layerForScrollCorner) { - m_layerForScrollCorner->removeFromParent(); - m_layerForScrollCorner = nullptr; - } - - m_renderView->frameView()->positionScrollbarLayers(); -} - -void RenderLayerCompositor::ensureRootLayer() -{ - RootLayerAttachment expectedAttachment = isMainFrame() ? RootLayerAttachedViaChromeClient : RootLayerAttachedViaEnclosingFrame; - if (expectedAttachment == m_rootLayerAttachment) - return; - - if (!m_rootContentLayer) { - m_rootContentLayer = GraphicsLayer::create(graphicsLayerFactory(), this); - IntRect overflowRect = m_renderView->pixelSnappedLayoutOverflowRect(); - m_rootContentLayer->setSize(FloatSize(overflowRect.maxX(), overflowRect.maxY())); - m_rootContentLayer->setPosition(FloatPoint()); - - // Need to clip to prevent transformed content showing outside this frame - m_rootContentLayer->setMasksToBounds(true); - } - - if (!m_overflowControlsHostLayer) { - ASSERT(!m_scrollLayer); - ASSERT(!m_containerLayer); - - // Create a layer to host the clipping layer and the overflow controls layers. - m_overflowControlsHostLayer = GraphicsLayer::create(graphicsLayerFactory(), this); - - // Create a clipping layer if this is an iframe or settings require to clip. - m_containerLayer = GraphicsLayer::create(graphicsLayerFactory(), this); - bool containerMasksToBounds = !isMainFrame(); - if (Settings* settings = m_renderView->document().settings()) { - if (settings->mainFrameClipsContent()) - containerMasksToBounds = true; - } - m_containerLayer->setMasksToBounds(containerMasksToBounds); - - m_scrollLayer = GraphicsLayer::create(graphicsLayerFactory(), this); - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->setLayerIsContainerForFixedPositionLayers(m_scrollLayer.get(), true); - - // Hook them up - m_overflowControlsHostLayer->addChild(m_containerLayer.get()); - m_containerLayer->addChild(m_scrollLayer.get()); - m_scrollLayer->addChild(m_rootContentLayer.get()); - - frameViewDidChangeSize(); - frameViewDidScroll(); - } - - // Check to see if we have to change the attachment - if (m_rootLayerAttachment != RootLayerUnattached) - detachRootLayer(); - - attachRootLayer(expectedAttachment); -} - -void RenderLayerCompositor::destroyRootLayer() -{ - if (!m_rootContentLayer) - return; - - detachRootLayer(); - -#if USE(RUBBER_BANDING) - if (m_layerForOverhangShadow) { - m_layerForOverhangShadow->removeFromParent(); - m_layerForOverhangShadow = nullptr; - } -#endif - - if (m_layerForHorizontalScrollbar) { - m_layerForHorizontalScrollbar->removeFromParent(); - m_layerForHorizontalScrollbar = nullptr; - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), HorizontalScrollbar); - if (Scrollbar* horizontalScrollbar = m_renderView->frameView()->verticalScrollbar()) - m_renderView->frameView()->invalidateScrollbar(horizontalScrollbar, IntRect(IntPoint(0, 0), horizontalScrollbar->frameRect().size())); - } - - if (m_layerForVerticalScrollbar) { - m_layerForVerticalScrollbar->removeFromParent(); - m_layerForVerticalScrollbar = nullptr; - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), VerticalScrollbar); - if (Scrollbar* verticalScrollbar = m_renderView->frameView()->verticalScrollbar()) - m_renderView->frameView()->invalidateScrollbar(verticalScrollbar, IntRect(IntPoint(0, 0), verticalScrollbar->frameRect().size())); - } - - if (m_layerForScrollCorner) { - m_layerForScrollCorner = nullptr; - m_renderView->frameView()->invalidateScrollCorner(m_renderView->frameView()->scrollCornerRect()); - } - - if (m_overflowControlsHostLayer) { - m_overflowControlsHostLayer = nullptr; - m_containerLayer = nullptr; - m_scrollLayer = nullptr; - } - ASSERT(!m_scrollLayer); - m_rootContentLayer = nullptr; -} - -void RenderLayerCompositor::attachRootLayer(RootLayerAttachment attachment) -{ - if (!m_rootContentLayer) - return; - - switch (attachment) { - case RootLayerUnattached: - ASSERT_NOT_REACHED(); - break; - case RootLayerAttachedViaChromeClient: { - Frame& frame = m_renderView->frameView()->frame(); - Page* page = frame.page(); - if (!page) - return; - page->chrome().client().attachRootGraphicsLayer(&frame, rootGraphicsLayer()); - break; - } - case RootLayerAttachedViaEnclosingFrame: { - // The layer will get hooked up via CompositedLayerMapping::updateGraphicsLayerConfiguration() - // for the frame's renderer in the parent document. - m_renderView->document().ownerElement()->scheduleLayerUpdate(); - break; - } - } - - m_rootLayerAttachment = attachment; -} - -void RenderLayerCompositor::detachRootLayer() -{ - if (!m_rootContentLayer || m_rootLayerAttachment == RootLayerUnattached) - return; - - switch (m_rootLayerAttachment) { - case RootLayerAttachedViaEnclosingFrame: { - // The layer will get unhooked up via CompositedLayerMapping::updateGraphicsLayerConfiguration() - // for the frame's renderer in the parent document. - if (m_overflowControlsHostLayer) - m_overflowControlsHostLayer->removeFromParent(); - else - m_rootContentLayer->removeFromParent(); - - if (HTMLFrameOwnerElement* ownerElement = m_renderView->document().ownerElement()) - ownerElement->scheduleLayerUpdate(); - break; - } - case RootLayerAttachedViaChromeClient: { - Frame& frame = m_renderView->frameView()->frame(); - Page* page = frame.page(); - if (!page) - return; - page->chrome().client().attachRootGraphicsLayer(&frame, 0); - } - break; - case RootLayerUnattached: - break; - } - - m_rootLayerAttachment = RootLayerUnattached; -} - -void RenderLayerCompositor::updateRootLayerAttachment() -{ - ensureRootLayer(); -} - -bool RenderLayerCompositor::isMainFrame() const -{ - // FIXME: Frame::isMainFrame() is probably better. - return !m_renderView->document().ownerElement(); -} - -// IFrames are special, because we hook compositing layers together across iframe boundaries -// when both parent and iframe content are composited. So when this frame becomes composited, we have -// to use a synthetic style change to get the iframes into RenderLayers in order to allow them to composite. -void RenderLayerCompositor::notifyIFramesOfCompositingChange() -{ - if (!m_renderView->frameView()) - return; - Frame& frame = m_renderView->frameView()->frame(); - - for (Frame* child = frame.tree().firstChild(); child; child = child->tree().traverseNext(&frame)) { - if (child->document() && child->document()->ownerElement()) - child->document()->ownerElement()->scheduleLayerUpdate(); - } - - // Compositing also affects the answer to RenderIFrame::requiresAcceleratedCompositing(), so - // we need to schedule a style recalc in our parent document. - if (HTMLFrameOwnerElement* ownerElement = m_renderView->document().ownerElement()) - ownerElement->scheduleLayerUpdate(); -} - -bool RenderLayerCompositor::layerHas3DContent(const RenderLayer* layer) const -{ - const RenderStyle* style = layer->renderer()->style(); - RenderLayerStackingNode* stackingNode = const_cast<RenderLayer*>(layer)->stackingNode(); - - if (style && - (style->transformStyle3D() == TransformStyle3DPreserve3D || - style->hasPerspective() || - style->transform().has3DOperation())) - return true; - - stackingNode->updateLayerListsIfNeeded(); - -#if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(stackingNode); -#endif - - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), AllChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) { - if (layerHas3DContent(curNode->layer())) - return true; - } - - return false; -} - -static bool isRootmostFixedOrStickyLayer(RenderLayer* layer) -{ - if (layer->renderer()->isStickyPositioned()) - return true; - - if (layer->renderer()->style()->position() != FixedPosition) - return false; - - for (RenderLayerStackingNode* stackingContainerNode = layer->stackingNode()->ancestorStackingContainerNode(); stackingContainerNode; stackingContainerNode = stackingContainerNode->ancestorStackingContainerNode()) { - if (stackingContainerNode->layer()->hasCompositedLayerMapping() && stackingContainerNode->layer()->renderer()->style()->position() == FixedPosition) - return false; - } - - return true; -} - -void RenderLayerCompositor::updateViewportConstraintStatus(RenderLayer* layer) -{ - if (isRootmostFixedOrStickyLayer(layer)) - addViewportConstrainedLayer(layer); - else - removeViewportConstrainedLayer(layer); -} - -void RenderLayerCompositor::addViewportConstrainedLayer(RenderLayer* layer) -{ - m_viewportConstrainedLayers.add(layer); -} - -void RenderLayerCompositor::removeViewportConstrainedLayer(RenderLayer* layer) -{ - if (!m_viewportConstrainedLayers.contains(layer)) - return; - - m_viewportConstrainedLayers.remove(layer); -} - -FixedPositionViewportConstraints RenderLayerCompositor::computeFixedViewportConstraints(RenderLayer* layer) const -{ - ASSERT(layer->hasCompositedLayerMapping()); - - FrameView* frameView = m_renderView->frameView(); - LayoutRect viewportRect = frameView->viewportConstrainedVisibleContentRect(); - - FixedPositionViewportConstraints constraints; - - GraphicsLayer* graphicsLayer = layer->compositedLayerMapping()->mainGraphicsLayer(); - - constraints.setLayerPositionAtLastLayout(graphicsLayer->position()); - constraints.setViewportRectAtLastLayout(viewportRect); - - RenderStyle* style = layer->renderer()->style(); - if (!style->left().isAuto()) - constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeLeft); - - if (!style->right().isAuto()) - constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeRight); - - if (!style->top().isAuto()) - constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeTop); - - if (!style->bottom().isAuto()) - constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeBottom); - - // If left and right are auto, use left. - if (style->left().isAuto() && style->right().isAuto()) - constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeLeft); - - // If top and bottom are auto, use top. - if (style->top().isAuto() && style->bottom().isAuto()) - constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeTop); - - return constraints; -} - -StickyPositionViewportConstraints RenderLayerCompositor::computeStickyViewportConstraints(RenderLayer* layer) const -{ - ASSERT(layer->hasCompositedLayerMapping()); - - FrameView* frameView = m_renderView->frameView(); - LayoutRect viewportRect = frameView->viewportConstrainedVisibleContentRect(); - - StickyPositionViewportConstraints constraints; - - RenderBoxModelObject* renderer = toRenderBoxModelObject(layer->renderer()); - - renderer->computeStickyPositionConstraints(constraints, viewportRect); - - GraphicsLayer* graphicsLayer = layer->compositedLayerMapping()->mainGraphicsLayer(); - - constraints.setLayerPositionAtLastLayout(graphicsLayer->position()); - constraints.setStickyOffsetAtLastLayout(renderer->stickyPositionOffset()); - - return constraints; -} - -ScrollingCoordinator* RenderLayerCompositor::scrollingCoordinator() const -{ - if (Page* page = this->page()) - return page->scrollingCoordinator(); - - return 0; -} - -GraphicsLayerFactory* RenderLayerCompositor::graphicsLayerFactory() const -{ - if (Page* page = this->page()) - return page->chrome().client().graphicsLayerFactory(); - return 0; -} - -Page* RenderLayerCompositor::page() const -{ - return m_renderView->frameView()->frame().page(); -} - -String RenderLayerCompositor::debugName(const GraphicsLayer* graphicsLayer) -{ - String name; - if (graphicsLayer == m_rootContentLayer.get()) { - name = "Content Root Layer"; -#if USE(RUBBER_BANDING) - } else if (graphicsLayer == m_layerForOverhangShadow.get()) { - name = "Overhang Areas Shadow"; -#endif - } else if (graphicsLayer == m_overflowControlsHostLayer.get()) { - name = "Overflow Controls Host Layer"; - } else if (graphicsLayer == m_layerForHorizontalScrollbar.get()) { - name = "Horizontal Scrollbar Layer"; - } else if (graphicsLayer == m_layerForVerticalScrollbar.get()) { - name = "Vertical Scrollbar Layer"; - } else if (graphicsLayer == m_layerForScrollCorner.get()) { - name = "Scroll Corner Layer"; - } else if (graphicsLayer == m_containerLayer.get()) { - name = "Frame Clipping Layer"; - } else if (graphicsLayer == m_scrollLayer.get()) { - name = "Frame Scrolling Layer"; - } else { - ASSERT_NOT_REACHED(); - } - - return name; -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerCompositor.h b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerCompositor.h deleted file mode 100644 index 162348c866c..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerCompositor.h +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright (C) 2009 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 RenderLayerCompositor_h -#define RenderLayerCompositor_h - -#include "core/page/ChromeClient.h" -#include "core/rendering/RenderLayer.h" -#include "platform/graphics/GraphicsLayerClient.h" -#include "wtf/HashMap.h" - -namespace WebCore { - -class FixedPositionViewportConstraints; -class GraphicsLayer; -class RenderEmbeddedObject; -class RenderLayerStackingNode; -class RenderPart; -class RenderVideo; -class ScrollingCoordinator; -class StickyPositionViewportConstraints; - - -enum CompositingUpdateType { - CompositingUpdateAfterStyleChange, - CompositingUpdateAfterLayout, - CompositingUpdateOnScroll, - CompositingUpdateOnCompositedScroll, - CompositingUpdateFinishAllDeferredWork -}; - -// RenderLayerCompositor manages the hierarchy of -// composited RenderLayers. It determines which RenderLayers -// become compositing, and creates and maintains a hierarchy of -// GraphicsLayers based on the RenderLayer painting order. -// -// There is one RenderLayerCompositor per RenderView. - -class RenderLayerCompositor : public GraphicsLayerClient { - WTF_MAKE_FAST_ALLOCATED; -public: - explicit RenderLayerCompositor(RenderView*); - ~RenderLayerCompositor(); - - // Return true if this RenderView is in "compositing mode" (i.e. has one or more - // composited RenderLayers) - bool inCompositingMode() const { return m_compositing; } - // 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; } - bool layerSquashingEnabled() const; - - bool canRender3DTransforms() const; - - // Copy the accelerated compositing related flags from Settings - void cacheAcceleratedCompositingFlags(); - - // Called when the layer hierarchy needs to be updated (compositing layers have been - // created, destroyed or re-parented). - void setCompositingLayersNeedRebuild(bool needRebuild = true); - bool compositingLayersNeedRebuild() const { return m_compositingLayersNeedRebuild; } - - // Called when something outside WebKit affects the visible rect (e.g. delegated scrolling). Might schedule a layer flush. - void didChangeVisibleRect(); - - // Updating properties required for determining if compositing is necessary. - void updateCompositingRequirementsState(); - void setNeedsUpdateCompositingRequirementsState() { m_needsUpdateCompositingRequirementsState = true; } - - // Main entry point for a full update. As needed, this function will compute compositing requirements, - // rebuild the composited layer tree, and/or update all the properties assocaited with each layer of the - // composited layer tree. - void updateCompositingLayers(CompositingUpdateType); - - // Update the compositing state of the given layer. Returns true if that state changed. - bool updateLayerCompositingState(RenderLayer*); - - // Update the geometry for compositing children of compositingAncestor. - void updateCompositingDescendantGeometry(RenderLayerStackingNode* compositingAncestor, RenderLayer*, bool compositedChildrenOnly); - - // Whether layer's compositedLayerMapping needs a GraphicsLayer to do clipping by an ancestor (non-stacking-context parent with overflow). - bool clippedByAncestor(const RenderLayer*) const; - // Whether layer's compositedLayerMapping needs a GraphicsLayer to clip z-order children of the given RenderLayer. - bool clipsCompositingDescendants(const RenderLayer*) const; - - // Whether the given layer needs an extra 'contents' layer. - bool needsContentsCompositingLayer(const RenderLayer*) const; - - bool supportsFixedRootBackgroundCompositing() const; - bool needsFixedRootBackgroundLayer(const RenderLayer*) const; - GraphicsLayer* fixedRootBackgroundLayer() const; - - // Return the bounding box required for compositing layer and its childern, relative to ancestorLayer. - // If layerBoundingBox is not 0, on return it contains the bounding box of this layer only. - IntRect calculateCompositedBounds(const RenderLayer*, const RenderLayer* ancestorLayer) const; - - // Repaint the appropriate layers when the given RenderLayer starts or stops being composited. - void repaintOnCompositingChange(RenderLayer*); - - void repaintInCompositedAncestor(RenderLayer*, const LayoutRect&); - - // Notify us that a layer has been added or removed - void layerWasAdded(RenderLayer* parent, RenderLayer* child); - void layerWillBeRemoved(RenderLayer* parent, RenderLayer* child); - - // Get the nearest ancestor layer that has overflow or clip, but is not a stacking context - RenderLayer* enclosingNonStackingClippingLayer(const RenderLayer* layer) const; - - // Repaint parts of all composited layers that intersect the given absolute rectangle (or the entire layer if the pointer is null). - void repaintCompositedLayers(const IntRect* = 0); - - RenderLayer* rootRenderLayer() const; - GraphicsLayer* rootGraphicsLayer() const; - GraphicsLayer* scrollLayer() const; - - enum RootLayerAttachment { - RootLayerUnattached, - RootLayerAttachedViaChromeClient, - RootLayerAttachedViaEnclosingFrame - }; - - RootLayerAttachment rootLayerAttachment() const { return m_rootLayerAttachment; } - void updateRootLayerAttachment(); - void updateRootLayerPosition(); - - void setIsInWindow(bool); - - void clearMappingForAllRenderLayers(); - - // Use by RenderVideo to ask if it should try to use accelerated compositing. - bool canAccelerateVideoRendering(RenderVideo*) const; - - // Walk the tree looking for layers with 3d transforms. Useful in case you need - // to know if there is non-affine content, e.g. for drawing into an image. - bool has3DContent() const; - - static RenderLayerCompositor* frameContentsCompositor(RenderPart*); - // Return true if the layers changed. - static bool parentFrameContentLayers(RenderPart*); - - // Update the geometry of the layers used for clipping and scrolling in frames. - void frameViewDidChangeLocation(const IntPoint& contentsOffset); - void frameViewDidChangeSize(); - void frameViewDidScroll(); - void frameViewDidLayout(); - void frameViewScrollbarsExistenceDidChange(); - void rootFixedBackgroundsChanged(); - - bool scrollingLayerDidChange(RenderLayer*); - - String layerTreeAsText(LayerTreeFlags); - - virtual void didCommitChangesForLayer(const GraphicsLayer*) const OVERRIDE; - - GraphicsLayer* layerForHorizontalScrollbar() const { return m_layerForHorizontalScrollbar.get(); } - GraphicsLayer* layerForVerticalScrollbar() const { return m_layerForVerticalScrollbar.get(); } - GraphicsLayer* layerForScrollCorner() const { return m_layerForScrollCorner.get(); } - - void updateViewportConstraintStatus(RenderLayer*); - void removeViewportConstrainedLayer(RenderLayer*); - - void addOutOfFlowPositionedLayer(RenderLayer*); - void removeOutOfFlowPositionedLayer(RenderLayer*); - - void resetTrackedRepaintRects(); - void setTracksRepaints(bool); - - void setNeedsToRecomputeCompositingRequirements() { m_needsToRecomputeCompositingRequirements = true; } - - virtual String debugName(const GraphicsLayer*) OVERRIDE; - -private: - class OverlapMap; - - // GraphicsLayerClient implementation - virtual void notifyAnimationStarted(const GraphicsLayer*, double, double) OVERRIDE { } - virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect&) OVERRIDE; - - virtual bool isTrackingRepaints() const OVERRIDE; - - // Whether the given RL needs to paint into its own separate backing (and hence would need its own CompositedLayerMapping). - bool needsOwnBacking(const RenderLayer*) const; - // Whether the layer could ever be composited. - bool canBeComposited(const RenderLayer*) const; - - // Returns all direct reasons that a layer should be composited. - CompositingReasons directReasonsForCompositing(const RenderLayer*) const; - - void updateDirectCompositingReasons(RenderLayer*); - - // Returns indirect reasons that a layer should be composited because of something in its subtree. - CompositingReasons subtreeReasonsForCompositing(RenderObject*, bool hasCompositedDescendants, bool has3DTransformedDescendants) const; - - // Make or destroy the CompositedLayerMapping for this layer; returns true if the compositedLayerMapping changed. - bool allocateOrClearCompositedLayerMapping(RenderLayer*); - - void clearMappingForRenderLayerIncludingDescendants(RenderLayer*); - - // Repaint the given rect (which is layer's coords), and regions of child layers that intersect that rect. - void recursiveRepaintLayer(RenderLayer*, const IntRect* = 0); - - void addToOverlapMap(OverlapMap&, RenderLayer*, IntRect& layerBounds, bool& boundsComputed); - void addToOverlapMapRecursive(OverlapMap&, RenderLayer*, RenderLayer* ancestorLayer = 0); - - struct SquashingState { - SquashingState() - : mostRecentMapping(0) - , hasMostRecentMapping(false) - , nextSquashedLayerIndex(0) { } - - void updateSquashingStateForNewMapping(CompositedLayerMappingPtr, bool hasNewCompositedLayerMapping, IntPoint newOffsetFromAbsolute); - - // The most recent composited backing that the layer should squash onto if needed. - CompositedLayerMappingPtr mostRecentMapping; - bool hasMostRecentMapping; - - // Offset in absolute coordinates of the compositedLayerMapping's owning layer. - IntPoint offsetFromAbsolute; - - // Counter that tracks what index the next RenderLayer would be if it gets squashed to the current squashing layer. - size_t nextSquashedLayerIndex; - }; - - // Forces an update for all frames of frame tree recursively. Used only when the mainFrame compositor is ready to - // finish all deferred work. - static void finishCompositingUpdateForFrameTree(Frame*); - - // Returns true if any layer's compositing changed - void computeCompositingRequirements(RenderLayer* ancestorLayer, RenderLayer*, OverlapMap*, struct CompositingRecursionData&, bool& descendantHas3DTransform, Vector<RenderLayer*>& unclippedDescendants); - - // Defines which RenderLayers will paint into which composited backings, by allocating and destroying CompositedLayerMappings as needed. - void assignLayersToBackings(RenderLayer*, bool& layersChanged); - void assignLayersToBackingsInternal(RenderLayer*, SquashingState&, 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, int depth); - - // Recurses down the tree, updating layer geometry only. - void updateLayerTreeGeometry(RenderLayer*); - - // Hook compositing layers together - void setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer); - void removeCompositedChildren(RenderLayer*); - - bool layerHas3DContent(const RenderLayer*) const; - bool isRunningAcceleratedTransformAnimation(RenderObject*) const; - - bool hasAnyAdditionalCompositedLayers(const RenderLayer* rootLayer) const; - - void ensureRootLayer(); - void destroyRootLayer(); - - void attachRootLayer(RootLayerAttachment); - void detachRootLayer(); - - bool isMainFrame() const; - - void updateOverflowControlsLayers(); - - void notifyIFramesOfCompositingChange(); - - Page* page() const; - - GraphicsLayerFactory* graphicsLayerFactory() const; - ScrollingCoordinator* scrollingCoordinator() const; - - // Whether a running transition or animation enforces the need for a compositing layer. - bool requiresCompositingForAnimation(RenderObject*) const; - // Whether a (not necessarily running) transition enforces the need for a compositing layer. - bool requiresCompositingForTransition(RenderObject*) const; - bool requiresCompositingForTransform(RenderObject*) const; - bool requiresCompositingForVideo(RenderObject*) const; - bool requiresCompositingForCanvas(RenderObject*) const; - bool requiresCompositingForPlugin(RenderObject*) const; - bool requiresCompositingForFrame(RenderObject*) const; - bool requiresCompositingForBackfaceVisibilityHidden(RenderObject*) const; - bool requiresCompositingForFilters(RenderObject*) const; - bool requiresCompositingForOverflowScrollingParent(const RenderLayer*) const; - bool requiresCompositingForOutOfFlowClipping(const RenderLayer*) const; - bool requiresCompositingForScrollableFrame() const; - bool requiresCompositingForPosition(RenderObject*, const RenderLayer*, RenderLayer::ViewportConstrainedNotCompositedReason* = 0) const; - bool requiresCompositingForOverflowScrolling(const RenderLayer*) const; - - void addViewportConstrainedLayer(RenderLayer*); - - FixedPositionViewportConstraints computeFixedViewportConstraints(RenderLayer*) const; - StickyPositionViewportConstraints computeStickyViewportConstraints(RenderLayer*) const; - - bool requiresHorizontalScrollbarLayer() const; - bool requiresVerticalScrollbarLayer() const; - bool requiresScrollCornerLayer() const; -#if USE(RUBBER_BANDING) - bool requiresOverhangLayers() const; -#endif - -private: - RenderView* m_renderView; - OwnPtr<GraphicsLayer> m_rootContentLayer; - - bool m_hasAcceleratedCompositing; - ChromeClient::CompositingTriggerFlags m_compositingTriggers; - - bool m_showRepaintCounter; - - // FIXME: This should absolutely not be mutable. - mutable bool m_needsToRecomputeCompositingRequirements; - bool m_needsToUpdateLayerTreeGeometry; - - bool m_compositing; - bool m_compositingLayersNeedRebuild; - bool m_forceCompositingMode; - bool m_inPostLayoutUpdate; // true when it's OK to trust layout information (e.g. layer sizes and positions) - bool m_needsUpdateCompositingRequirementsState; - - bool m_isTrackingRepaints; // Used for testing. - - RootLayerAttachment m_rootLayerAttachment; - - // Enclosing container layer, which clips for iframe content - OwnPtr<GraphicsLayer> m_containerLayer; - OwnPtr<GraphicsLayer> m_scrollLayer; - - HashSet<RenderLayer*> m_viewportConstrainedLayers; - HashSet<RenderLayer*> m_viewportConstrainedLayersNeedingUpdate; - - // This is used in updateCompositingRequirementsState to avoid full tree - // walks while determining if layers have unclipped descendants. - HashSet<RenderLayer*> m_outOfFlowPositionedLayers; - - // Enclosing layer for overflow controls and the clipping layer - OwnPtr<GraphicsLayer> m_overflowControlsHostLayer; - - // Layers for overflow controls - OwnPtr<GraphicsLayer> m_layerForHorizontalScrollbar; - OwnPtr<GraphicsLayer> m_layerForVerticalScrollbar; - OwnPtr<GraphicsLayer> m_layerForScrollCorner; -#if USE(RUBBER_BANDING) - OwnPtr<GraphicsLayer> m_layerForOverhangShadow; -#endif -}; - - -} // namespace WebCore - -#endif // RenderLayerCompositor_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerFilterInfo.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerFilterInfo.cpp index 600ced9e77a..1d0ff416d46 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerFilterInfo.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerFilterInfo.cpp @@ -39,8 +39,6 @@ #include "core/svg/SVGFilterElement.h" #include "core/svg/SVGFilterPrimitiveStandardAttributes.h" #include "core/svg/graphics/filters/SVGFilter.h" -#include "platform/graphics/filters/custom/CustomFilterOperation.h" -#include "platform/graphics/filters/custom/CustomFilterProgram.h" namespace WebCore { @@ -95,7 +93,6 @@ RenderLayerFilterInfo::RenderLayerFilterInfo(RenderLayer* layer) RenderLayerFilterInfo::~RenderLayerFilterInfo() { - removeCustomFilterClients(); removeReferenceFilterClients(); } @@ -107,8 +104,12 @@ void RenderLayerFilterInfo::setRenderer(PassRefPtr<FilterEffectRenderer> rendere void RenderLayerFilterInfo::notifyFinished(Resource*) { RenderObject* renderer = m_layer->renderer(); - toElement(renderer->node())->scheduleLayerUpdate(); - renderer->repaint(); + // FIXME: This caller of scheduleSVGFilterLayerUpdateHack() is not correct. It's using the layer update + // system to trigger a RenderLayer to go through the filter updating logic, but that might not + // even happen if this element is style sharing and RenderObject::setStyle() returns early. + // Filters need to find a better way to hook into the system. + toElement(renderer->node())->scheduleSVGFilterLayerUpdateHack(); + renderer->paintInvalidationForWholeRenderer(); } void RenderLayerFilterInfo::updateReferenceFilterClients(const FilterOperations& operations) @@ -130,7 +131,7 @@ void RenderLayerFilterInfo::updateReferenceFilterClients(const FilterOperations& // Reference is internal; add layer as a client so we can trigger // filter repaint on SVG attribute change. Element* filter = m_layer->renderer()->node()->document().getElementById(referenceFilterOperation->fragment()); - if (!filter || !filter->hasTagName(SVGNames::filterTag)) + if (!isSVGFilterElement(filter)) continue; if (filter->renderer()) toRenderSVGResourceContainer(filter->renderer())->addClientRenderLayer(m_layer); @@ -156,39 +157,5 @@ void RenderLayerFilterInfo::removeReferenceFilterClients() m_internalSVGReferences.clear(); } -void RenderLayerFilterInfo::notifyCustomFilterProgramLoaded(CustomFilterProgram*) -{ - RenderObject* renderer = m_layer->renderer(); - toElement(renderer->node())->scheduleLayerUpdate(); - 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->type() != FilterOperation::CUSTOM) - continue; - RefPtr<CustomFilterProgram> program = toCustomFilterOperation(filterOperation)->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(); -} - } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerFilterInfo.h b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerFilterInfo.h index f982008fc55..4c84861c4b2 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerFilterInfo.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerFilterInfo.h @@ -34,7 +34,6 @@ #include "core/fetch/DocumentResource.h" #include "platform/geometry/LayoutRect.h" #include "platform/graphics/filters/FilterOperation.h" -#include "platform/graphics/filters/custom/CustomFilterProgramClient.h" #include "wtf/HashMap.h" #include "wtf/PassRefPtr.h" #include "wtf/RefPtr.h" @@ -48,7 +47,7 @@ class RenderLayerFilterInfo; typedef HashMap<const RenderLayer*, RenderLayerFilterInfo*> RenderLayerFilterInfoMap; -class RenderLayerFilterInfo : public CustomFilterProgramClient, public DocumentResourceClient { +class RenderLayerFilterInfo FINAL : public DocumentResourceClient { public: static RenderLayerFilterInfo* filterInfoForRenderLayer(const RenderLayer*); static RenderLayerFilterInfo* createFilterInfoForRenderLayerIfNeeded(RenderLayer*); @@ -61,30 +60,21 @@ public: FilterEffectRenderer* renderer() const { return m_renderer.get(); } void setRenderer(PassRefPtr<FilterEffectRenderer>); - // Implementation of the CustomFilterProgramClient interface. - virtual void notifyCustomFilterProgramLoaded(CustomFilterProgram*); - - void updateCustomFilterClients(const FilterOperations&); - void removeCustomFilterClients(); - void updateReferenceFilterClients(const FilterOperations&); - virtual void notifyFinished(Resource*); + virtual void notifyFinished(Resource*) OVERRIDE; void removeReferenceFilterClients(); private: RenderLayerFilterInfo(RenderLayer*); - ~RenderLayerFilterInfo(); + virtual ~RenderLayerFilterInfo(); RenderLayer* m_layer; RefPtr<FilterEffectRenderer> m_renderer; LayoutRect m_dirtySourceRect; - typedef Vector<RefPtr<CustomFilterProgram> > CustomFilterProgramList; - CustomFilterProgramList m_cachedCustomFilterPrograms; - static RenderLayerFilterInfoMap* s_filterMap; - Vector<RefPtr<Element> > m_internalSVGReferences; + WillBePersistentHeapVector<RefPtrWillBeMember<Element> > m_internalSVGReferences; Vector<ResourcePtr<DocumentResource> > m_externalSVGReferences; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerModelObject.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerModelObject.cpp index 801c0af5199..cb617a2e8a4 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerModelObject.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerModelObject.cpp @@ -25,7 +25,7 @@ #include "config.h" #include "core/rendering/RenderLayerModelObject.h" -#include "core/frame/Frame.h" +#include "core/frame/LocalFrame.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderView.h" @@ -53,10 +53,10 @@ void RenderLayerModelObject::destroyLayer() m_layer = nullptr; } -void RenderLayerModelObject::createLayer() +void RenderLayerModelObject::createLayer(LayerType type) { ASSERT(!m_layer); - m_layer = adoptPtr(new RenderLayer(this)); + m_layer = adoptPtr(new RenderLayer(this, type)); setHasLayer(true); m_layer->insertOnlyThisLayer(); } @@ -75,7 +75,7 @@ void RenderLayerModelObject::willBeDestroyed() { if (isPositioned()) { // Don't use this->view() because the document's renderView has been set to 0 during destruction. - if (Frame* frame = this->frame()) { + if (LocalFrame* frame = this->frame()) { if (FrameView* frameView = frame->view()) { if (style()->hasViewportConstrainedPosition()) frameView->removeViewportConstrainedObject(this); @@ -88,43 +88,29 @@ void RenderLayerModelObject::willBeDestroyed() destroyLayer(); } -void RenderLayerModelObject::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) +void RenderLayerModelObject::styleWillChange(StyleDifference diff, const RenderStyle& newStyle) { s_wasFloating = isFloating(); // If our z-index changes value or our visibility changes, // we need to dirty our stacking context's z-order list. RenderStyle* oldStyle = style(); - if (oldStyle && newStyle) { - if (parent()) { - // Do a repaint with the old style first, e.g., for example if we go from - // having an outline to not having an outline. - if (diff == StyleDifferenceRepaintLayer) { - layer()->repainter().repaintIncludingDescendants(); - if (!(oldStyle->clip() == newStyle->clip())) - layer()->clipper().clearClipRectsIncludingDescendants(); - } else if (diff == StyleDifferenceRepaint || newStyle->outlineSize() < oldStyle->outlineSize()) - repaint(); - } - - if (diff == StyleDifferenceLayout || diff == StyleDifferenceSimplifiedLayout) { - // When a layout hint happens, we go ahead and do a repaint of the layer, since the layer could - // end up being destroyed. + if (oldStyle) { + // Do a repaint with the old style first through RenderLayerRepainter. + // RenderObject::styleWillChange takes care of repainting objects without RenderLayers. + if (parent() && diff.needsRepaintLayer()) { + layer()->repainter().repaintIncludingNonCompositingDescendants(); + if (oldStyle->hasClip() != newStyle.hasClip() + || oldStyle->clip() != newStyle.clip()) + layer()->clipper().clearClipRectsIncludingDescendants(); + } else if (diff.needsFullLayout()) { if (hasLayer()) { - if (oldStyle->position() != newStyle->position() - || oldStyle->zIndex() != newStyle->zIndex() - || oldStyle->hasAutoZIndex() != newStyle->hasAutoZIndex() - || !(oldStyle->clip() == newStyle->clip()) - || oldStyle->hasClip() != newStyle->hasClip() - || oldStyle->opacity() != newStyle->opacity() - || oldStyle->transform() != newStyle->transform() - || oldStyle->filter() != newStyle->filter() - ) - layer()->repainter().repaintIncludingDescendants(); - } else if (newStyle->hasTransform() || newStyle->opacity() < 1 || newStyle->hasFilter()) { + if (!layer()->hasCompositedLayerMapping() && oldStyle->position() != newStyle.position()) + layer()->repainter().repaintIncludingNonCompositingDescendants(); + } 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(); + paintInvalidationForWholeRenderer(); } } } @@ -135,22 +121,27 @@ void RenderLayerModelObject::styleWillChange(StyleDifference diff, const RenderS void RenderLayerModelObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { bool hadTransform = hasTransform(); - bool hadLayer = hasLayer(); - bool layerWasSelfPainting = hadLayer && layer()->isSelfPaintingLayer(); RenderObject::styleDidChange(diff, oldStyle); updateFromStyle(); - if (requiresLayer()) { + LayerType type = layerTypeRequired(); + if (type != NoLayer) { if (!layer() && layerCreationAllowedForSubtree()) { if (s_wasFloating && isFloating()) setChildNeedsLayout(); - createLayer(); + createLayer(type); if (parent() && !needsLayout() && containingBlock()) { - layer()->repainter().setRepaintStatus(NeedsFullRepaint); - // There is only one layer to update, it is not worth using |cachedOffset| since - // we are not sure the value will be used. - layer()->updateLayerPositions(0); + // FIXME: This invalidation is overly broad. We should update to + // do the correct invalidation at RenderStyle::diff time. crbug.com/349061 + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + layer()->renderer()->setShouldDoFullPaintInvalidationAfterLayout(true); + else + layer()->repainter().setRepaintStatus(NeedsFullRepaint); + // Hit in animations/interpolation/perspective-interpolation.html + // FIXME: I suspect we can remove this assert disabler now. + DisableCompositingQueryAsserts disabler; + layer()->updateLayerPositionRecursive(); } } } else if (layer() && layer()->parent()) { @@ -160,13 +151,14 @@ void RenderLayerModelObject::styleDidChange(StyleDifference diff, const RenderSt if (s_wasFloating && isFloating()) setChildNeedsLayout(); if (hadTransform) - setNeedsLayoutAndPrefWidthsRecalc(); + setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } if (layer()) { + // FIXME: Ideally we shouldn't need this setter but we can't easily infer an overflow-only layer + // from the style. + layer()->setLayerType(type); layer()->styleChanged(diff, oldStyle); - if (hadLayer && layer()->isSelfPaintingLayer() != layerWasSelfPainting) - setChildNeedsLayout(); } if (FrameView *frameView = view()->frameView()) { diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerModelObject.h b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerModelObject.h index 4eb42633a7f..d3153e6217e 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerModelObject.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerModelObject.h @@ -23,7 +23,7 @@ #ifndef RenderLayerModelObject_h #define RenderLayerModelObject_h -#include "core/rendering/CompositedLayerMappingPtr.h" +#include "core/rendering/compositing/CompositedLayerMappingPtr.h" #include "core/rendering/RenderObject.h" namespace WebCore { @@ -32,6 +32,15 @@ class RenderLayer; class CompositedLayerMapping; class ScrollableArea; +enum LayerType { + NoLayer, + NormalLayer, + // A forced or overflow clip layer is required for bookkeeping purposes, + // but does not force a layer to be self painting. + OverflowClipLayer, + ForcedLayer +}; + class RenderLayerModelObject : public RenderObject { public: explicit RenderLayerModelObject(ContainerNode*); @@ -44,11 +53,11 @@ public: RenderLayer* layer() const { return m_layer.get(); } ScrollableArea* scrollableArea() const; - virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle) OVERRIDE; + virtual void styleWillChange(StyleDifference, const RenderStyle& newStyle) OVERRIDE; virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; virtual void updateFromStyle() { } - virtual bool requiresLayer() const = 0; + virtual LayerType layerTypeRequired() const = 0; // Returns true if the background is painted opaque in the given rect. // The query rect is given in local coordinate system. @@ -62,7 +71,7 @@ public: CompositedLayerMapping* groupedMapping() const; protected: - void createLayer(); + void createLayer(LayerType); virtual void willBeDestroyed() OVERRIDE; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerReflectionInfo.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerReflectionInfo.cpp index 38801bdbdc4..f6e2d9e5de3 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerReflectionInfo.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerReflectionInfo.cpp @@ -55,20 +55,20 @@ namespace WebCore { -RenderLayerReflectionInfo::RenderLayerReflectionInfo(RenderBox* renderer) - : m_renderer(renderer) +RenderLayerReflectionInfo::RenderLayerReflectionInfo(RenderBox& renderer) + : m_box(renderer) , m_isPaintingInsideReflection(false) { - UseCounter::count(m_renderer->document(), UseCounter::Reflection); + UseCounter::count(m_box.document(), UseCounter::Reflection); - m_reflection = RenderReplica::createAnonymous(&(m_renderer->document())); - m_reflection->setParent(m_renderer); // We create a 1-way connection. + m_reflection = RenderReplica::createAnonymous(&(m_box.document())); + m_reflection->setParent(&m_box); // We create a 1-way connection. } RenderLayerReflectionInfo::~RenderLayerReflectionInfo() { if (!m_reflection->documentBeingDestroyed()) - m_reflection->removeLayers(renderer()->layer()); + m_reflection->removeLayers(m_box.layer()); m_reflection->setParent(0); m_reflection->destroy(); @@ -84,16 +84,16 @@ RenderLayer* RenderLayerReflectionInfo::reflectionLayer() const void RenderLayerReflectionInfo::updateAfterStyleChange(const RenderStyle* oldStyle) { RefPtr<RenderStyle> newStyle = RenderStyle::create(); - newStyle->inheritFrom(renderer()->style()); + newStyle->inheritFrom(m_box.style()); // Map in our transform. TransformOperations transform; - switch (renderer()->style()->boxReflect()->direction()) { + switch (m_box.style()->boxReflect()->direction()) { case ReflectionBelow: transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), Length(100., Percent), TransformOperation::Translate)); transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), - renderer()->style()->boxReflect()->offset(), TransformOperation::Translate)); + m_box.style()->boxReflect()->offset(), TransformOperation::Translate)); transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::Scale)); break; @@ -102,14 +102,14 @@ void RenderLayerReflectionInfo::updateAfterStyleChange(const RenderStyle* oldSty transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), Length(100., Percent), TransformOperation::Translate)); transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), - renderer()->style()->boxReflect()->offset(), TransformOperation::Translate)); + m_box.style()->boxReflect()->offset(), TransformOperation::Translate)); break; case ReflectionRight: transform.operations().append(TranslateTransformOperation::create(Length(100., Percent), Length(0, Fixed), TransformOperation::Translate)); transform.operations().append(TranslateTransformOperation::create( - renderer()->style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::Translate)); + m_box.style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::Translate)); transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::Scale)); break; @@ -118,13 +118,13 @@ void RenderLayerReflectionInfo::updateAfterStyleChange(const RenderStyle* oldSty transform.operations().append(TranslateTransformOperation::create(Length(100., Percent), Length(0, Fixed), TransformOperation::Translate)); transform.operations().append(TranslateTransformOperation::create( - renderer()->style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::Translate)); + m_box.style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::Translate)); break; } newStyle->setTransform(transform); // Map in our mask. - newStyle->setMaskBoxImage(renderer()->style()->boxReflect()->mask()); + newStyle->setMaskBoxImage(m_box.style()->boxReflect()->mask()); m_reflection->setStyle(newStyle.release()); } @@ -142,7 +142,7 @@ void RenderLayerReflectionInfo::paint(GraphicsContext* context, const LayerPaint String RenderLayerReflectionInfo::debugName() const { - return renderer()->debugName() + " (reflection)"; + return m_box.debugName() + " (reflection)"; } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerReflectionInfo.h b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerReflectionInfo.h index 90ec7898acf..83009eb0b91 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerReflectionInfo.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerReflectionInfo.h @@ -57,7 +57,7 @@ class RenderReplica; class RenderLayerReflectionInfo { WTF_MAKE_NONCOPYABLE(RenderLayerReflectionInfo); public: - explicit RenderLayerReflectionInfo(RenderBox*); + explicit RenderLayerReflectionInfo(RenderBox&); ~RenderLayerReflectionInfo(); RenderReplica* reflection() const { return m_reflection; } @@ -72,9 +72,7 @@ public: String debugName() const; private: - RenderBox* renderer() const { return m_renderer; } - - RenderBox* m_renderer; + RenderBox& m_box; RenderReplica* m_reflection; // A state bit tracking if we are painting inside a replica. diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerRepainter.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerRepainter.cpp index 77da5c125d9..d502c3cf52c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerRepainter.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerRepainter.cpp @@ -44,44 +44,49 @@ #include "config.h" #include "core/rendering/RenderLayerRepainter.h" -#include "core/rendering/CompositedLayerMapping.h" #include "core/rendering/FilterEffectRenderer.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderView.h" +#include "core/rendering/compositing/CompositedLayerMapping.h" namespace WebCore { -RenderLayerRepainter::RenderLayerRepainter(RenderLayerModelObject* renderer) +RenderLayerRepainter::RenderLayerRepainter(RenderLayerModelObject& renderer) : m_renderer(renderer) , m_repaintStatus(NeedsNormalRepaint) { } -void RenderLayerRepainter::repaintAfterLayout(RenderGeometryMap* geometryMap, bool shouldCheckForRepaint) +void RenderLayerRepainter::repaintAfterLayout(bool shouldCheckForRepaint) { - if (m_renderer->layer()->hasVisibleContent()) { - RenderView* view = m_renderer->view(); + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + return; + + // FIXME: really, we're in the repaint phase here, and the following queries are legal. + // Until those states are fully fledged, I'll just disable the ASSERTS. + DisableCompositingQueryAsserts disabler; + if (m_renderer.layer()->hasVisibleContent()) { + RenderView* view = m_renderer.view(); ASSERT(view); // FIXME: LayoutState does not work with RenderLayers as there is not a 1-to-1 // mapping between them and the RenderObjects. It would be neat to enable // LayoutState outside the layout() phase and use it here. - ASSERT(!view->layoutStateEnabled()); + ASSERT(!view->layoutStateCachedOffsetsEnabled()); - RenderLayerModelObject* repaintContainer = m_renderer->containerForRepaint(); + const RenderLayerModelObject* repaintContainer = m_renderer.containerForPaintInvalidation(); LayoutRect oldRepaintRect = m_repaintRect; - LayoutRect oldOutlineBox = m_outlineBox; - computeRepaintRects(repaintContainer, geometryMap); + LayoutPoint oldOffset = m_offset; + computeRepaintRects(); + shouldCheckForRepaint &= shouldRepaintLayer(); - // FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same - // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048 if (shouldCheckForRepaint) { if (view && !view->document().printing()) { if (m_repaintStatus & NeedsFullRepaint) { - m_renderer->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldRepaintRect)); + m_renderer.invalidatePaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldRepaintRect), InvalidationLayer); if (m_repaintRect != oldRepaintRect) - m_renderer->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_repaintRect)); - } else if (shouldRepaintAfterLayout()) { - m_renderer->repaintAfterLayoutIfNeeded(repaintContainer, m_renderer->selfNeedsLayout(), oldRepaintRect, oldOutlineBox, &m_repaintRect, &m_outlineBox); + m_renderer.invalidatePaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_repaintRect), InvalidationLayer); + } else { + m_renderer.invalidatePaintAfterLayoutIfNeeded(repaintContainer, m_renderer.selfNeedsLayout(), oldRepaintRect, oldOffset, &m_repaintRect, &m_offset); } } } @@ -95,57 +100,83 @@ void RenderLayerRepainter::repaintAfterLayout(RenderGeometryMap* geometryMap, bo void RenderLayerRepainter::clearRepaintRects() { - ASSERT(!m_renderer->layer()->hasVisibleContent()); + ASSERT(!m_renderer.layer()->hasVisibleContent()); m_repaintRect = IntRect(); - m_outlineBox = IntRect(); } -void RenderLayerRepainter::computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap) +void RenderLayerRepainter::computeRepaintRects() { - m_repaintRect = m_renderer->clippedOverflowRectForRepaint(repaintContainer); - m_outlineBox = m_renderer->outlineBoundsForRepaint(repaintContainer, geometryMap); + const RenderLayerModelObject* repaintContainer = m_renderer.containerForPaintInvalidation(); + LayoutRect repaintRect = m_renderer.boundsRectForPaintInvalidation(repaintContainer); + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) { + // FIXME: We want RenderLayerRepainter to go away when + // repaint-after-layout is on by default so we need to figure out how to + // handle this update. + m_renderer.setPreviousPaintInvalidationRect(repaintRect); + } else { + m_repaintRect = repaintRect; + m_offset = RenderLayer::positionFromPaintInvalidationContainer(&m_renderer, repaintContainer); + } } -void RenderLayerRepainter::computeRepaintRectsIncludingDescendants() +void RenderLayerRepainter::computeRepaintRectsIncludingNonCompositingDescendants() { // FIXME: computeRepaintRects() has to walk up the parent chain for every layer to compute the rects. // We should make this more efficient. // FIXME: it's wrong to call this when layout is not up-to-date, which we do. - computeRepaintRects(m_renderer->containerForRepaint()); + computeRepaintRects(); - for (RenderLayer* layer = m_renderer->layer()->firstChild(); layer; layer = layer->nextSibling()) - layer->repainter().computeRepaintRectsIncludingDescendants(); + for (RenderLayer* layer = m_renderer.layer()->firstChild(); layer; layer = layer->nextSibling()) { + if (layer->compositingState() != PaintsIntoOwnBacking && layer->compositingState() != PaintsIntoGroupedBacking) + layer->repainter().computeRepaintRectsIncludingNonCompositingDescendants(); + } } -inline bool RenderLayerRepainter::shouldRepaintAfterLayout() const +inline bool RenderLayerRepainter::shouldRepaintLayer() const { - if (m_repaintStatus == NeedsNormalRepaint) + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + return false; + + if (m_repaintStatus != NeedsFullRepaintForPositionedMovementLayout) return true; // Composited layers that were moved during a positioned movement only // layout, don't need to be repainted. They just need to be recomposited. - ASSERT(m_repaintStatus == NeedsFullRepaintForPositionedMovementLayout); - return m_renderer->compositingState() != PaintsIntoOwnBacking; + return m_renderer.compositingState() != PaintsIntoOwnBacking; } // Since we're only painting non-composited layers, we know that they all share the same repaintContainer. -void RenderLayerRepainter::repaintIncludingNonCompositingDescendants(RenderLayerModelObject* repaintContainer) +void RenderLayerRepainter::repaintIncludingNonCompositingDescendants() { - m_renderer->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_renderer->clippedOverflowRectForRepaint(repaintContainer))); + repaintIncludingNonCompositingDescendantsInternal(m_renderer.containerForPaintInvalidation()); +} - for (RenderLayer* curr = m_renderer->layer()->firstChild(); curr; curr = curr->nextSibling()) { - if (!curr->hasCompositedLayerMapping()) - curr->repainter().repaintIncludingNonCompositingDescendants(repaintContainer); +void RenderLayerRepainter::repaintIncludingNonCompositingDescendantsInternal(const RenderLayerModelObject* repaintContainer) +{ + m_renderer.invalidatePaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_renderer.boundsRectForPaintInvalidation(repaintContainer)), InvalidationLayer); + + // FIXME: Repaints can be issued during style recalc at present, via RenderLayerModelObject::styleWillChange. This happens in scenarios when + // repaint is needed but not layout. + DisableCompositingQueryAsserts disabler; + + for (RenderLayer* curr = m_renderer.layer()->firstChild(); curr; curr = curr->nextSibling()) { + if (curr->compositingState() != PaintsIntoOwnBacking && curr->compositingState() != PaintsIntoGroupedBacking) + curr->repainter().repaintIncludingNonCompositingDescendantsInternal(repaintContainer); } } LayoutRect RenderLayerRepainter::repaintRectIncludingNonCompositingDescendants() const { - LayoutRect repaintRect = m_repaintRect; - for (RenderLayer* child = m_renderer->layer()->firstChild(); child; child = child->nextSibling()) { + LayoutRect repaintRect; + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + repaintRect = m_renderer.previousPaintInvalidationRect(); + else + repaintRect = m_repaintRect; + + for (RenderLayer* child = m_renderer.layer()->firstChild(); child; child = child->nextSibling()) { // Don't include repaint rects for composited child layers; they will paint themselves and have a different origin. - if (child->hasCompositedLayerMapping()) + if (child->compositingState() == PaintsIntoOwnBacking || child->compositingState() == PaintsIntoGroupedBacking) continue; repaintRect.unite(child->repainter().repaintRectIncludingNonCompositingDescendants()); @@ -153,80 +184,55 @@ LayoutRect RenderLayerRepainter::repaintRectIncludingNonCompositingDescendants() return repaintRect; } -void RenderLayerRepainter::setBackingNeedsRepaint() -{ - ASSERT(m_renderer->compositingState() != NotComposited); - - if (m_renderer->compositingState() == PaintsIntoGroupedBacking) { - // FIXME: should probably setNeedsDisplayInRect for this layer's bounds only. - m_renderer->groupedMapping()->squashingLayer()->setNeedsDisplay(); - } else { - m_renderer->compositedLayerMapping()->setContentsNeedDisplay(); - } -} - void RenderLayerRepainter::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(m_renderer->compositingState() != NotComposited); - if (m_renderer->compositingState() == NotComposited) { + ASSERT(m_renderer.compositingState() != NotComposited); + if (m_renderer.compositingState() == NotComposited) { // If we're trying to repaint the placeholder document layer, propagate the // repaint to the native view system. LayoutRect absRect(r); LayoutPoint delta; - m_renderer->layer()->convertToLayerCoords(m_renderer->layer()->root(), delta); + m_renderer.layer()->convertToLayerCoords(m_renderer.layer()->root(), delta); absRect.moveBy(delta); - RenderView* view = m_renderer->view(); + if (absRect.isEmpty()) + return; + + RenderView* view = m_renderer.view(); if (view) view->repaintViewRectangle(absRect); + return; + } + IntRect repaintRect = pixelSnappedIntRect(r); + // FIXME: generalize accessors to backing GraphicsLayers so that this code is squashing-agnostic. + if (m_renderer.groupedMapping()) { + if (GraphicsLayer* squashingLayer = m_renderer.groupedMapping()->squashingLayer()) + squashingLayer->setNeedsDisplayInRect(repaintRect); } else { - if (m_renderer->compositingState() == PaintsIntoGroupedBacking) { - // FIXME: LayoutRect rounding to IntRect is probably not a good idea. - IntRect offsetRect = pixelSnappedIntRect(r); - if (m_renderer->hasTransform()) - offsetRect = m_renderer->layer()->transform()->mapRect(pixelSnappedIntRect(r)); - - offsetRect.move(-m_renderer->layer()->offsetFromSquashingLayerOrigin()); - m_renderer->groupedMapping()->squashingLayer()->setNeedsDisplayInRect(offsetRect); - } else { - m_renderer->compositedLayerMapping()->setContentsNeedDisplayInRect(pixelSnappedIntRect(r)); - } + m_renderer.compositedLayerMapping()->setContentsNeedDisplayInRect(repaintRect); } } -void RenderLayerRepainter::repaintIncludingDescendants() -{ - m_renderer->repaint(); - for (RenderLayer* curr = m_renderer->layer()->firstChild(); curr; curr = curr->nextSibling()) - curr->repainter().repaintIncludingDescendants(); -} - void RenderLayerRepainter::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect) { if (rect.isEmpty()) return; - LayoutRect rectForRepaint = rect; - m_renderer->style()->filterOutsets().expandRect(rectForRepaint); + m_renderer.style()->filterOutsets().expandRect(rectForRepaint); - RenderLayerFilterInfo* filterInfo = m_renderer->layer()->filterInfo(); + RenderLayerFilterInfo* filterInfo = m_renderer.layer()->filterInfo(); ASSERT(filterInfo); filterInfo->expandDirtySourceRect(rectForRepaint); - 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(m_renderer->layer()->calculateLayerBounds(m_renderer->layer())); - } - RenderLayer* parentLayer = enclosingFilterRepaintLayer(); ASSERT(parentLayer); FloatQuad repaintQuad(rectForRepaint); - LayoutRect parentLayerRect = m_renderer->localToContainerQuad(repaintQuad, parentLayer->renderer()).enclosingBoundingBox(); + LayoutRect parentLayerRect = m_renderer.localToContainerQuad(repaintQuad, parentLayer->renderer()).enclosingBoundingBox(); + + if (parentLayerRect.isEmpty()) + return; if (parentLayer->hasCompositedLayerMapping()) { parentLayer->repainter().setBackingNeedsRepaintInRect(parentLayerRect); @@ -249,8 +255,8 @@ void RenderLayerRepainter::setFilterBackendNeedsRepaintingInRect(const LayoutRec RenderLayer* RenderLayerRepainter::enclosingFilterRepaintLayer() const { - for (const RenderLayer* curr = m_renderer->layer(); curr; curr = curr->parent()) { - if ((curr != m_renderer->layer() && curr->requiresFullLayerImageForFilters()) || curr->compositingState() == PaintsIntoOwnBacking || curr->isRootLayer()) + for (const RenderLayer* curr = m_renderer.layer(); curr; curr = curr->parent()) { + if ((curr != m_renderer.layer() && curr->requiresFullLayerImageForFilters()) || curr->compositingState() == PaintsIntoOwnBacking || curr->isRootLayer()) return const_cast<RenderLayer*>(curr); } return 0; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerRepainter.h b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerRepainter.h index ffc08ee8947..b55d89d0ffd 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerRepainter.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerRepainter.h @@ -53,51 +53,50 @@ namespace WebCore { enum RepaintStatus { NeedsNormalRepaint = 0, NeedsFullRepaint = 1 << 0, - NeedsFullRepaintForPositionedMovementLayout = 1 << 1 + NeedsFullRepaintForPositionedMovementLayout = NeedsFullRepaint | 1 << 1 }; -class RenderGeometryMap; class RenderLayer; class RenderLayerModelObject; class RenderLayerRepainter { WTF_MAKE_NONCOPYABLE(RenderLayerRepainter); public: - RenderLayerRepainter(RenderLayerModelObject*); + RenderLayerRepainter(RenderLayerModelObject&); - // Return a cached repaint rect, computed relative to the layer renderer's containerForRepaint. + // Return a cached repaint rect, computed relative to the layer renderer's containerForPaintInvalidation. LayoutRect repaintRect() const { return m_repaintRect; } LayoutRect repaintRectIncludingNonCompositingDescendants() const; - void repaintAfterLayout(RenderGeometryMap*, bool shouldCheckForRepaint); - void repaintIncludingNonCompositingDescendants(RenderLayerModelObject* repaintContainer); - void repaintIncludingDescendants(); + void repaintAfterLayout(bool shouldCheckForRepaint); + void repaintIncludingNonCompositingDescendants(); void setRepaintStatus(RepaintStatus status) { m_repaintStatus = status; } - void computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* = 0); - void computeRepaintRectsIncludingDescendants(); + void computeRepaintRects(); + void computeRepaintRectsIncludingNonCompositingDescendants(); // Indicate that the layer contents need to be repainted. Only has an effect // if layer compositing is being used, - void setBackingNeedsRepaint(); void setBackingNeedsRepaintInRect(const LayoutRect&); // r is in the coordinate space of the layer's render object void setFilterBackendNeedsRepaintingInRect(const LayoutRect&); private: - bool shouldRepaintAfterLayout() const; + void repaintIncludingNonCompositingDescendantsInternal(const RenderLayerModelObject* repaintContainer); + + bool shouldRepaintLayer() const; void clearRepaintRects(); RenderLayer* enclosingFilterRepaintLayer() const; - RenderLayerModelObject* m_renderer; + RenderLayerModelObject& m_renderer; unsigned m_repaintStatus; // RepaintStatus LayoutRect m_repaintRect; // Cached repaint rects. Used by layout. - LayoutRect m_outlineBox; + LayoutPoint m_offset; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerScrollableArea.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerScrollableArea.cpp index 0486111467d..b9512464833 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerScrollableArea.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerScrollableArea.cpp @@ -47,20 +47,21 @@ #include "core/css/PseudoStyleRequest.h" #include "core/dom/shadow/ShadowRoot.h" #include "core/editing/FrameSelection.h" +#include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/html/HTMLFrameOwnerElement.h" #include "core/inspector/InspectorInstrumentation.h" +#include "core/inspector/InspectorTraceEvents.h" #include "core/page/EventHandler.h" #include "core/page/FocusController.h" -#include "core/frame/Frame.h" -#include "core/frame/FrameView.h" #include "core/page/Page.h" #include "core/page/scrolling/ScrollingCoordinator.h" -#include "core/rendering/CompositedLayerMapping.h" #include "core/rendering/RenderGeometryMap.h" -#include "core/rendering/RenderLayerCompositor.h" #include "core/rendering/RenderScrollbar.h" #include "core/rendering/RenderScrollbarPart.h" #include "core/rendering/RenderView.h" +#include "core/rendering/compositing/CompositedLayerMapping.h" +#include "core/rendering/compositing/RenderLayerCompositor.h" #include "platform/PlatformGestureEvent.h" #include "platform/PlatformMouseEvent.h" #include "platform/graphics/GraphicsContextStateSaver.h" @@ -73,21 +74,18 @@ namespace WebCore { const int ResizerControlExpandRatioForTouch = 2; -RenderLayerScrollableArea::RenderLayerScrollableArea(RenderBox* box) - : m_box(box) +RenderLayerScrollableArea::RenderLayerScrollableArea(RenderLayer& layer) + : m_layer(layer) , m_inResizeMode(false) + , m_scrollsOverflow(false) , m_scrollDimensionsDirty(true) , m_inOverflowRelayout(false) - , m_needsCompositedScrolling(false) - , m_willUseCompositedScrollingHasBeenRecorded(false) - , m_isScrollableAreaHasBeenRecorded(false) - , m_forceNeedsCompositedScrolling(DoNotForceCompositedScrolling) , m_scrollCorner(0) , m_resizer(0) { ScrollableArea::setConstrainsScrollingToContentEdge(false); - Node* node = m_box->node(); + Node* node = box().node(); if (node && node->isElementNode()) { // We save and restore only the scrollOffset as the other scroll values are recalculated. Element* element = toElement(node); @@ -102,31 +100,31 @@ RenderLayerScrollableArea::RenderLayerScrollableArea(RenderBox* box) RenderLayerScrollableArea::~RenderLayerScrollableArea() { - if (inResizeMode() && !m_box->documentBeingDestroyed()) { - if (Frame* frame = m_box->frame()) + if (inResizeMode() && !box().documentBeingDestroyed()) { + if (LocalFrame* frame = box().frame()) frame->eventHandler().resizeScrollableAreaDestroyed(); } - if (Frame* frame = m_box->frame()) { + if (LocalFrame* frame = box().frame()) { if (FrameView* frameView = frame->view()) { frameView->removeScrollableArea(this); } } - if (m_box->frame() && m_box->frame()->page()) { - if (ScrollingCoordinator* scrollingCoordinator = m_box->frame()->page()->scrollingCoordinator()) + if (box().frame() && box().frame()->page()) { + if (ScrollingCoordinator* scrollingCoordinator = box().frame()->page()->scrollingCoordinator()) scrollingCoordinator->willDestroyScrollableArea(this); } - if (!m_box->documentBeingDestroyed()) { - Node* node = m_box->node(); + if (!box().documentBeingDestroyed()) { + Node* node = box().node(); if (node && node->isElementNode()) toElement(node)->setSavedLayerScrollOffset(m_scrollOffset); } - if (Frame* frame = m_box->frame()) { + if (LocalFrame* frame = box().frame()) { if (FrameView* frameView = frame->view()) - frameView->removeResizerArea(m_box); + frameView->removeResizerArea(box()); } destroyScrollbar(HorizontalScrollbar); @@ -138,38 +136,40 @@ RenderLayerScrollableArea::~RenderLayerScrollableArea() m_resizer->destroy(); } -ScrollableArea* RenderLayerScrollableArea::enclosingScrollableArea() const -{ - if (RenderBox* enclosingScrollableBox = m_box->enclosingScrollableBox()) - return enclosingScrollableBox->layer()->scrollableArea(); - - // FIXME: We should return the frame view here (or possibly an ancestor frame view, - // if the frame view isn't scrollable. - return 0; -} - GraphicsLayer* RenderLayerScrollableArea::layerForScrolling() const { - return m_box->hasCompositedLayerMapping() ? m_box->compositedLayerMapping()->scrollingContentsLayer() : 0; + return box().hasCompositedLayerMapping() ? box().compositedLayerMapping()->scrollingContentsLayer() : 0; } GraphicsLayer* RenderLayerScrollableArea::layerForHorizontalScrollbar() const { - return m_box->hasCompositedLayerMapping() ? m_box->compositedLayerMapping()->layerForHorizontalScrollbar() : 0; + // See crbug.com/343132. + DisableCompositingQueryAsserts disabler; + + return box().hasCompositedLayerMapping() ? box().compositedLayerMapping()->layerForHorizontalScrollbar() : 0; } GraphicsLayer* RenderLayerScrollableArea::layerForVerticalScrollbar() const { - return m_box->hasCompositedLayerMapping() ? m_box->compositedLayerMapping()->layerForVerticalScrollbar() : 0; + // See crbug.com/343132. + DisableCompositingQueryAsserts disabler; + + return box().hasCompositedLayerMapping() ? box().compositedLayerMapping()->layerForVerticalScrollbar() : 0; } GraphicsLayer* RenderLayerScrollableArea::layerForScrollCorner() const { - return m_box->hasCompositedLayerMapping() ? m_box->compositedLayerMapping()->layerForScrollCorner() : 0; + // See crbug.com/343132. + DisableCompositingQueryAsserts disabler; + + return box().hasCompositedLayerMapping() ? box().compositedLayerMapping()->layerForScrollCorner() : 0; } void RenderLayerScrollableArea::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect) { + // See crbug.com/343132. + DisableCompositingQueryAsserts disabler; + if (scrollbar == m_vBar.get()) { if (GraphicsLayer* layer = layerForVerticalScrollbar()) { layer->setNeedsDisplayInRect(rect); @@ -184,14 +184,34 @@ void RenderLayerScrollableArea::invalidateScrollbarRect(Scrollbar* scrollbar, co IntRect scrollRect = rect; // If we are not yet inserted into the tree, there is no need to repaint. - if (!m_box->parent()) + if (!box().parent()) return; if (scrollbar == m_vBar.get()) - scrollRect.move(verticalScrollbarStart(0, m_box->width()), m_box->borderTop()); + scrollRect.move(verticalScrollbarStart(0, box().width()), box().borderTop()); else - scrollRect.move(horizontalScrollbarStart(0), m_box->height() - m_box->borderBottom() - scrollbar->height()); - m_box->repaintRectangle(scrollRect); + scrollRect.move(horizontalScrollbarStart(0), box().height() - box().borderBottom() - scrollbar->height()); + + if (scrollRect.isEmpty()) + return; + + LayoutRect repaintRect = scrollRect; + box().flipForWritingMode(repaintRect); + + IntRect intRect = pixelSnappedIntRect(repaintRect); + + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && box().frameView()->isInPerformLayout()) { + if (scrollbar == m_vBar.get()) { + m_verticalBarDamage = intRect; + m_hasVerticalBarDamage = true; + } else { + m_horizontalBarDamage = intRect; + m_hasHorizontalBarDamage = true; + } + + } else { + box().invalidatePaintRectangle(intRect); + } } void RenderLayerScrollableArea::invalidateScrollCornerRect(const IntRect& rect) @@ -202,14 +222,14 @@ void RenderLayerScrollableArea::invalidateScrollCornerRect(const IntRect& rect) } if (m_scrollCorner) - m_scrollCorner->repaintRectangle(rect); + m_scrollCorner->invalidatePaintRectangle(rect); if (m_resizer) - m_resizer->repaintRectangle(rect); + m_resizer->invalidatePaintRectangle(rect); } bool RenderLayerScrollableArea::isActive() const { - Page* page = m_box->frame()->page(); + Page* page = box().frame()->page(); return page && page->focusController().isActive(); } @@ -258,53 +278,53 @@ IntRect RenderLayerScrollableArea::scrollCornerRect() const // (b) Both scrollbars are present. bool hasHorizontalBar = horizontalScrollbar(); bool hasVerticalBar = verticalScrollbar(); - bool hasResizer = m_box->style()->resize() != RESIZE_NONE; + bool hasResizer = box().style()->resize() != RESIZE_NONE; if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar))) - return cornerRect(m_box->style(), horizontalScrollbar(), verticalScrollbar(), m_box->pixelSnappedBorderBoxRect()); + return cornerRect(box().style(), horizontalScrollbar(), verticalScrollbar(), box().pixelSnappedBorderBoxRect()); return IntRect(); } IntRect RenderLayerScrollableArea::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const { - RenderView* view = m_box->view(); + RenderView* view = box().view(); if (!view) return scrollbarRect; IntRect rect = scrollbarRect; rect.move(scrollbarOffset(scrollbar)); - return view->frameView()->convertFromRenderer(m_box, rect); + return view->frameView()->convertFromRenderer(box(), rect); } IntRect RenderLayerScrollableArea::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const { - RenderView* view = m_box->view(); + RenderView* view = box().view(); if (!view) return parentRect; - IntRect rect = view->frameView()->convertToRenderer(m_box, parentRect); + IntRect rect = view->frameView()->convertToRenderer(box(), parentRect); rect.move(-scrollbarOffset(scrollbar)); return rect; } IntPoint RenderLayerScrollableArea::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const { - RenderView* view = m_box->view(); + RenderView* view = box().view(); if (!view) return scrollbarPoint; IntPoint point = scrollbarPoint; point.move(scrollbarOffset(scrollbar)); - return view->frameView()->convertFromRenderer(m_box, point); + return view->frameView()->convertFromRenderer(box(), point); } IntPoint RenderLayerScrollableArea::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const { - RenderView* view = m_box->view(); + RenderView* view = box().view(); if (!view) return parentPoint; - IntPoint point = view->frameView()->convertToRenderer(m_box, parentPoint); + IntPoint point = view->frameView()->convertToRenderer(box(), parentPoint); point.move(-scrollbarOffset(scrollbar)); return point; @@ -318,7 +338,7 @@ int RenderLayerScrollableArea::scrollSize(ScrollbarOrientation orientation) cons void RenderLayerScrollableArea::setScrollOffset(const IntPoint& newScrollOffset) { - if (!m_box->isMarquee()) { + if (!box().isMarquee()) { // Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks). if (m_scrollDimensionsDirty) computeScrollDimensions(); @@ -329,62 +349,77 @@ void RenderLayerScrollableArea::setScrollOffset(const IntPoint& newScrollOffset) setScrollOffset(toIntSize(newScrollOffset)); - Frame* frame = m_box->frame(); - InspectorInstrumentation::willScrollLayer(m_box); + LocalFrame* frame = box().frame(); + ASSERT(frame); - RenderView* view = m_box->view(); + RefPtr<FrameView> frameView = box().frameView(); - // We should have a RenderView if we're trying to scroll. - ASSERT(view); + TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ScrollLayer", "data", InspectorScrollLayerEvent::data(&box())); + // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. + InspectorInstrumentation::willScrollLayer(&box()); // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll). // We don't update compositing layers, because we need to do a deep update from the compositing ancestor. - bool inLayout = view ? view->frameView()->isInLayout() : false; - if (!inLayout) { + if (!frameView->isInPerformLayout()) { // If we're in the middle of layout, we'll just update layers once layout has finished. layer()->updateLayerPositionsAfterOverflowScroll(); - if (view) { - // Update regions, scrolling may change the clip of a particular region. - view->frameView()->updateAnnotatedRegions(); - view->updateWidgetPositions(); - } - + // Update regions, scrolling may change the clip of a particular region. + frameView->updateAnnotatedRegions(); + // FIXME: We shouldn't call updateWidgetPositions() here since it might tear down the render tree, + // for now we just crash to avoid allowing an attacker to use after free. + frameView->updateWidgetPositions(); + RELEASE_ASSERT(frameView->renderView()); updateCompositingLayersAfterScroll(); } - RenderLayerModelObject* repaintContainer = m_box->containerForRepaint(); - if (frame) { - // The caret rect needs to be invalidated after scrolling - frame->selection().setCaretRectNeedsUpdate(); + const RenderLayerModelObject* repaintContainer = box().containerForPaintInvalidation(); + // The caret rect needs to be invalidated after scrolling + frame->selection().setCaretRectNeedsUpdate(); - FloatQuad quadForFakeMouseMoveEvent = FloatQuad(layer()->repainter().repaintRect()); - if (repaintContainer) - quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent); - frame->eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent); - } + FloatQuad quadForFakeMouseMoveEvent; + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + quadForFakeMouseMoveEvent = FloatQuad(layer()->renderer()->previousPaintInvalidationRect()); + else + quadForFakeMouseMoveEvent = FloatQuad(layer()->repainter().repaintRect()); + + quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent); + frame->eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent); bool requiresRepaint = true; - if (m_box->view()->compositor()->inCompositingMode()) { + if (box().view()->compositor()->inCompositingMode()) { + // Hits in virtual/gpu/fast/canvas/canvas-scroll-path-into-view.html. + DisableCompositingQueryAsserts disabler; bool onlyScrolledCompositedLayers = scrollsOverflow() && !layer()->hasVisibleNonLayerContent() && !layer()->hasNonCompositedChild() && !layer()->hasBlockSelectionGapBounds() - && !m_box->isMarquee(); + && !box().isMarquee(); if (usesCompositedScrolling() || onlyScrolledCompositedLayers) requiresRepaint = false; } // Just schedule a full repaint of our object. - if (view && requiresRepaint) - m_box->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(layer()->repainter().repaintRect())); + if (requiresRepaint) { + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) { + if (box().frameView()->isInPerformLayout()) + box().setShouldDoFullPaintInvalidationAfterLayout(true); + else + box().invalidatePaintUsingContainer(repaintContainer, pixelSnappedIntRect(layer()->renderer()->previousPaintInvalidationRect()), InvalidationScroll); + } else { + box().invalidatePaintUsingContainer(repaintContainer, pixelSnappedIntRect(layer()->repainter().repaintRect()), InvalidationScroll); + } + } // Schedule the scroll DOM event. - if (m_box->node()) - m_box->node()->document().enqueueScrollEventForNode(m_box->node()); + if (box().node()) + box().node()->document().enqueueScrollEventForNode(box().node()); - InspectorInstrumentation::didScrollLayer(m_box); + if (AXObjectCache* cache = box().document().existingAXObjectCache()) + cache->handleScrollPositionChanged(&box()); + + InspectorInstrumentation::didScrollLayer(&box()); } IntPoint RenderLayerScrollableArea::scrollPosition() const @@ -399,10 +434,10 @@ IntPoint RenderLayerScrollableArea::minimumScrollPosition() const IntPoint RenderLayerScrollableArea::maximumScrollPosition() const { - if (!m_box->hasOverflowClip()) + if (!box().hasOverflowClip()) return -scrollOrigin(); - return -scrollOrigin() + enclosingIntRect(m_overflowRect).size() - enclosingIntRect(m_box->clientBoxRect()).size(); + return -scrollOrigin() + enclosingIntRect(m_overflowRect).size() - enclosingIntRect(box().clientBoxRect()).size(); } IntRect RenderLayerScrollableArea::visibleContentRect(IncludeScrollbarsInRect scrollbarInclusion) const @@ -440,12 +475,12 @@ IntSize RenderLayerScrollableArea::overhangAmount() const IntPoint RenderLayerScrollableArea::lastKnownMousePosition() const { - return m_box->frame() ? m_box->frame()->eventHandler().lastKnownMousePosition() : IntPoint(); + return box().frame() ? box().frame()->eventHandler().lastKnownMousePosition() : IntPoint(); } bool RenderLayerScrollableArea::shouldSuspendScrollAnimations() const { - RenderView* view = m_box->view(); + RenderView* view = box().view(); if (!view) return true; return view->frameView()->shouldSuspendScrollAnimations(); @@ -453,7 +488,7 @@ bool RenderLayerScrollableArea::shouldSuspendScrollAnimations() const bool RenderLayerScrollableArea::scrollbarsCanBeActive() const { - RenderView* view = m_box->view(); + RenderView* view = box().view(); if (!view) return false; return view->frameView()->scrollbarsCanBeActive(); @@ -461,62 +496,67 @@ bool RenderLayerScrollableArea::scrollbarsCanBeActive() const IntRect RenderLayerScrollableArea::scrollableAreaBoundingBox() const { - return m_box->absoluteBoundingBoxRect(); + return box().absoluteBoundingBoxRect(); } bool RenderLayerScrollableArea::userInputScrollable(ScrollbarOrientation orientation) const { - if (m_box->isIntristicallyScrollable(orientation)) + if (box().isIntristicallyScrollable(orientation)) return true; EOverflow overflowStyle = (orientation == HorizontalScrollbar) ? - m_box->style()->overflowX() : m_box->style()->overflowY(); + box().style()->overflowX() : box().style()->overflowY(); return (overflowStyle == OSCROLL || overflowStyle == OAUTO || overflowStyle == OOVERLAY); } bool RenderLayerScrollableArea::shouldPlaceVerticalScrollbarOnLeft() const { - return m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft(); + return box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft(); } int RenderLayerScrollableArea::pageStep(ScrollbarOrientation orientation) const { int length = (orientation == HorizontalScrollbar) ? - m_box->pixelSnappedClientWidth() : m_box->pixelSnappedClientHeight(); + box().pixelSnappedClientWidth() : box().pixelSnappedClientHeight(); int minPageStep = static_cast<float>(length) * ScrollableArea::minFractionToStepWhenPaging(); int pageStep = max(minPageStep, length - ScrollableArea::maxOverlapBetweenPages()); return max(pageStep, 1); } +RenderBox& RenderLayerScrollableArea::box() const +{ + return *m_layer.renderBox(); +} + RenderLayer* RenderLayerScrollableArea::layer() const { - return m_box->layer(); + return &m_layer; } -int RenderLayerScrollableArea::scrollWidth() const +LayoutUnit RenderLayerScrollableArea::scrollWidth() const { if (m_scrollDimensionsDirty) const_cast<RenderLayerScrollableArea*>(this)->computeScrollDimensions(); - return snapSizeToPixel(m_overflowRect.width(), m_box->clientLeft() + m_box->x()); + return m_overflowRect.width(); } -int RenderLayerScrollableArea::scrollHeight() const +LayoutUnit RenderLayerScrollableArea::scrollHeight() const { if (m_scrollDimensionsDirty) const_cast<RenderLayerScrollableArea*>(this)->computeScrollDimensions(); - return snapSizeToPixel(m_overflowRect.height(), m_box->clientTop() + m_box->y()); + return m_overflowRect.height(); } void RenderLayerScrollableArea::computeScrollDimensions() { m_scrollDimensionsDirty = false; - m_overflowRect = m_box->layoutOverflowRect(); - m_box->flipForWritingMode(m_overflowRect); + m_overflowRect = box().layoutOverflowRect(); + box().flipForWritingMode(m_overflowRect); - int scrollableLeftOverflow = m_overflowRect.x() - m_box->borderLeft() - (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? m_box->verticalScrollbarWidth() : 0); - int scrollableTopOverflow = m_overflowRect.y() - m_box->borderTop(); + int scrollableLeftOverflow = m_overflowRect.x() - box().borderLeft() - (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? box().verticalScrollbarWidth() : 0); + int scrollableTopOverflow = m_overflowRect.y() - box().borderTop(); setScrollOrigin(IntPoint(-scrollableLeftOverflow, -scrollableTopOverflow)); } @@ -530,7 +570,7 @@ void RenderLayerScrollableArea::scrollToOffset(const IntSize& scrollOffset, Scro void RenderLayerScrollableArea::updateAfterLayout() { // List box parts handle the scrollbars by themselves so we have nothing to do. - if (m_box->style()->appearance() == ListboxPart) + if (box().style()->appearance() == ListboxPart) return; m_scrollDimensionsDirty = true; @@ -538,7 +578,7 @@ void RenderLayerScrollableArea::updateAfterLayout() computeScrollDimensions(); - if (!m_box->isMarquee()) { + if (!box().isMarquee()) { // 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). IntSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset()); @@ -552,87 +592,97 @@ void RenderLayerScrollableArea::updateAfterLayout() bool hasHorizontalOverflow = this->hasHorizontalOverflow(); bool hasVerticalOverflow = this->hasVerticalOverflow(); - // overflow:scroll should just enable/disable. - if (m_box->style()->overflowX() == OSCROLL) - horizontalScrollbar()->setEnabled(hasHorizontalOverflow); - if (m_box->style()->overflowY() == OSCROLL) - verticalScrollbar()->setEnabled(hasVerticalOverflow); + { + // Hits in compositing/overflow/automatically-opt-into-composited-scrolling-after-style-change.html. + DisableCompositingQueryAsserts disabler; + + // overflow:scroll should just enable/disable. + if (box().style()->overflowX() == OSCROLL) + horizontalScrollbar()->setEnabled(hasHorizontalOverflow); + if (box().style()->overflowY() == OSCROLL) + verticalScrollbar()->setEnabled(hasVerticalOverflow); + } // overflow:auto may need to lay out again if scrollbars got added/removed. - bool autoHorizontalScrollBarChanged = m_box->hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow); - bool autoVerticalScrollBarChanged = m_box->hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow); + bool autoHorizontalScrollBarChanged = box().hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow); + bool autoVerticalScrollBarChanged = box().hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow); if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) { - if (m_box->hasAutoHorizontalScrollbar()) + if (box().hasAutoHorizontalScrollbar()) setHasHorizontalScrollbar(hasHorizontalOverflow); - if (m_box->hasAutoVerticalScrollbar()) + if (box().hasAutoVerticalScrollbar()) setHasVerticalScrollbar(hasVerticalOverflow); + if (hasVerticalOverflow || hasHorizontalOverflow) + updateScrollCornerStyle(); + layer()->updateSelfPaintingLayer(); // Force an update since we know the scrollbars have changed things. - if (m_box->document().hasAnnotatedRegions()) - m_box->document().setAnnotatedRegionsDirty(true); + if (box().document().hasAnnotatedRegions()) + box().document().setAnnotatedRegionsDirty(true); - m_box->repaint(); + if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + box().paintInvalidationForWholeRenderer(); - if (m_box->style()->overflowX() == OAUTO || m_box->style()->overflowY() == OAUTO) { + if (box().style()->overflowX() == OAUTO || box().style()->overflowY() == OAUTO) { if (!m_inOverflowRelayout) { // Our proprietary overflow: overlay value doesn't trigger a layout. m_inOverflowRelayout = true; - SubtreeLayoutScope layoutScope(m_box); - layoutScope.setNeedsLayout(m_box); - if (m_box->isRenderBlock()) { - RenderBlock* block = toRenderBlock(m_box); - block->scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged); - block->layoutBlock(true); + SubtreeLayoutScope layoutScope(box()); + layoutScope.setNeedsLayout(&box()); + if (box().isRenderBlock()) { + RenderBlock& block = toRenderBlock(box()); + block.scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged); + block.layoutBlock(true); } else { - m_box->layout(); + box().layout(); } m_inOverflowRelayout = false; } } } - // Set up the range (and page step/line step). - if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) { - int clientWidth = m_box->pixelSnappedClientWidth(); - horizontalScrollbar->setProportion(clientWidth, overflowRect().width()); - } - if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) { - int clientHeight = m_box->pixelSnappedClientHeight(); - verticalScrollbar->setProportion(clientHeight, overflowRect().height()); + { + // Hits in compositing/overflow/automatically-opt-into-composited-scrolling-after-style-change.html. + DisableCompositingQueryAsserts disabler; + + // Set up the range (and page step/line step). + if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) { + int clientWidth = box().pixelSnappedClientWidth(); + horizontalScrollbar->setProportion(clientWidth, overflowRect().width()); + } + if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) { + int clientHeight = box().pixelSnappedClientHeight(); + verticalScrollbar->setProportion(clientHeight, overflowRect().height()); + } } updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow()); - - // Composited scrolling may need to be enabled or disabled if the amount of overflow changed. - if (m_box->view() && m_box->view()->compositor()->updateLayerCompositingState(m_box->layer())) - m_box->view()->compositor()->setCompositingLayersNeedRebuild(); } bool RenderLayerScrollableArea::hasHorizontalOverflow() const { ASSERT(!m_scrollDimensionsDirty); - return scrollWidth() > m_box->pixelSnappedClientWidth(); + return scrollWidth() > box().clientWidth(); } bool RenderLayerScrollableArea::hasVerticalOverflow() const { ASSERT(!m_scrollDimensionsDirty); - return scrollHeight() > m_box->pixelSnappedClientHeight(); + return scrollHeight() > box().clientHeight(); } bool RenderLayerScrollableArea::hasScrollableHorizontalOverflow() const { - return hasHorizontalOverflow() && m_box->scrollsOverflowX(); + return hasHorizontalOverflow() && box().scrollsOverflowX(); } bool RenderLayerScrollableArea::hasScrollableVerticalOverflow() const { - return hasVerticalOverflow() && m_box->scrollsOverflowY(); + return hasVerticalOverflow() && box().scrollsOverflowY(); } static bool overflowRequiresScrollbar(EOverflow overflow) @@ -648,14 +698,18 @@ static bool overflowDefinesAutomaticScrollbar(EOverflow overflow) void RenderLayerScrollableArea::updateAfterStyleChange(const RenderStyle* oldStyle) { // List box parts handle the scrollbars by themselves so we have nothing to do. - if (m_box->style()->appearance() == ListboxPart) + if (box().style()->appearance() == ListboxPart) + return; + + // RenderView shouldn't provide scrollbars on its own. + if (box().isRenderView()) return; if (!m_scrollDimensionsDirty) updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow()); - EOverflow overflowX = m_box->style()->overflowX(); - EOverflow overflowY = m_box->style()->overflowY(); + EOverflow overflowX = box().style()->overflowX(); + EOverflow overflowY = box().style()->overflowY(); // To avoid doing a relayout in updateScrollbarsAfterLayout, we try to keep any automatic scrollbar that was already present. bool needsHorizontalScrollbar = (hasHorizontalScrollbar() && overflowDefinesAutomaticScrollbar(overflowX)) || overflowRequiresScrollbar(overflowX); @@ -686,10 +740,35 @@ void RenderLayerScrollableArea::updateAfterStyleChange(const RenderStyle* oldSty updateResizerStyle(); } +void RenderLayerScrollableArea::updateAfterCompositingChange() +{ + layer()->updateScrollingStateAfterCompositingChange(); +} + +void RenderLayerScrollableArea::updateAfterOverflowRecalc() +{ + computeScrollDimensions(); + if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) { + int clientWidth = box().pixelSnappedClientWidth(); + horizontalScrollbar->setProportion(clientWidth, overflowRect().width()); + } + if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) { + int clientHeight = box().pixelSnappedClientHeight(); + verticalScrollbar->setProportion(clientHeight, overflowRect().height()); + } + + bool hasHorizontalOverflow = this->hasHorizontalOverflow(); + bool hasVerticalOverflow = this->hasVerticalOverflow(); + bool autoHorizontalScrollBarChanged = box().hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow); + bool autoVerticalScrollBarChanged = box().hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow); + if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) + box().setNeedsLayoutAndFullPaintInvalidation(); +} + IntSize RenderLayerScrollableArea::clampScrollOffset(const IntSize& scrollOffset) const { - int maxX = scrollWidth() - m_box->pixelSnappedClientWidth(); - int maxY = scrollHeight() - m_box->pixelSnappedClientHeight(); + int maxX = scrollWidth() - box().pixelSnappedClientWidth(); + int maxY = scrollHeight() - box().pixelSnappedClientHeight(); int x = std::max(std::min(scrollOffset.width(), maxX), 0); int y = std::max(std::min(scrollOffset.height(), maxY), 0); @@ -704,8 +783,8 @@ IntRect RenderLayerScrollableArea::rectForHorizontalScrollbar(const IntRect& bor const IntRect& scrollCorner = scrollCornerRect(); return IntRect(horizontalScrollbarStart(borderBoxRect.x()), - borderBoxRect.maxY() - m_box->borderBottom() - m_hBar->height(), - borderBoxRect.width() - (m_box->borderLeft() + m_box->borderRight()) - scrollCorner.width(), + borderBoxRect.maxY() - box().borderBottom() - m_hBar->height(), + borderBoxRect.width() - (box().borderLeft() + box().borderRight()) - scrollCorner.width(), m_hBar->height()); } @@ -717,54 +796,54 @@ IntRect RenderLayerScrollableArea::rectForVerticalScrollbar(const IntRect& borde const IntRect& scrollCorner = scrollCornerRect(); return IntRect(verticalScrollbarStart(borderBoxRect.x(), borderBoxRect.maxX()), - borderBoxRect.y() + m_box->borderTop(), + borderBoxRect.y() + box().borderTop(), m_vBar->width(), - borderBoxRect.height() - (m_box->borderTop() + m_box->borderBottom()) - scrollCorner.height()); + borderBoxRect.height() - (box().borderTop() + box().borderBottom()) - scrollCorner.height()); } LayoutUnit RenderLayerScrollableArea::verticalScrollbarStart(int minX, int maxX) const { - if (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) - return minX + m_box->borderLeft(); - return maxX - m_box->borderRight() - m_vBar->width(); + if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) + return minX + box().borderLeft(); + return maxX - box().borderRight() - m_vBar->width(); } LayoutUnit RenderLayerScrollableArea::horizontalScrollbarStart(int minX) const { - int x = minX + m_box->borderLeft(); - if (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) - x += m_vBar ? m_vBar->width() : resizerCornerRect(m_box->pixelSnappedBorderBoxRect(), ResizerForPointer).width(); + int x = minX + box().borderLeft(); + if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) + x += m_vBar ? m_vBar->width() : resizerCornerRect(box().pixelSnappedBorderBoxRect(), ResizerForPointer).width(); return x; } IntSize RenderLayerScrollableArea::scrollbarOffset(const Scrollbar* scrollbar) const { if (scrollbar == m_vBar.get()) - return IntSize(verticalScrollbarStart(0, m_box->width()), m_box->borderTop()); + return IntSize(verticalScrollbarStart(0, box().width()), box().borderTop()); if (scrollbar == m_hBar.get()) - return IntSize(horizontalScrollbarStart(0), m_box->height() - m_box->borderBottom() - scrollbar->height()); + return IntSize(horizontalScrollbarStart(0), box().height() - box().borderBottom() - scrollbar->height()); ASSERT_NOT_REACHED(); return IntSize(); } -static inline RenderObject* rendererForScrollbar(RenderObject* renderer) +static inline RenderObject* rendererForScrollbar(RenderObject& renderer) { - if (Node* node = renderer->node()) { + if (Node* node = renderer.node()) { if (ShadowRoot* shadowRoot = node->containingShadowRoot()) { if (shadowRoot->type() == ShadowRoot::UserAgentShadowRoot) return shadowRoot->host()->renderer(); } } - return renderer; + return &renderer; } PassRefPtr<Scrollbar> RenderLayerScrollableArea::createScrollbar(ScrollbarOrientation orientation) { RefPtr<Scrollbar> widget; - RenderObject* actualRenderer = rendererForScrollbar(m_box); + RenderObject* actualRenderer = rendererForScrollbar(box()); bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style()->hasPseudoStyle(SCROLLBAR); if (hasCustomScrollbarStyle) { widget = RenderScrollbar::createCustomScrollbar(this, orientation, actualRenderer->node()); @@ -775,7 +854,7 @@ PassRefPtr<Scrollbar> RenderLayerScrollableArea::createScrollbar(ScrollbarOrient else didAddScrollbar(widget.get(), VerticalScrollbar); } - m_box->document().view()->addChild(widget.get()); + box().document().view()->addChild(widget.get()); return widget.release(); } @@ -790,7 +869,7 @@ void RenderLayerScrollableArea::destroyScrollbar(ScrollbarOrientation orientatio scrollbar->removeFromParent(); scrollbar->disconnectFromScrollableArea(); - scrollbar = 0; + scrollbar = nullptr; } void RenderLayerScrollableArea::setHasHorizontalScrollbar(bool hasScrollbar) @@ -798,10 +877,14 @@ void RenderLayerScrollableArea::setHasHorizontalScrollbar(bool hasScrollbar) if (hasScrollbar == hasHorizontalScrollbar()) return; - if (hasScrollbar) + if (hasScrollbar) { + // This doesn't hit in any tests, but since the equivalent code in setHasVerticalScrollbar + // does, presumably this code does as well. + DisableCompositingQueryAsserts disabler; m_hBar = createScrollbar(HorizontalScrollbar); - else + } else { destroyScrollbar(HorizontalScrollbar); + } // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style. if (m_hBar) @@ -810,8 +893,8 @@ void RenderLayerScrollableArea::setHasHorizontalScrollbar(bool hasScrollbar) m_vBar->styleChanged(); // Force an update since we know the scrollbars have changed things. - if (m_box->document().hasAnnotatedRegions()) - m_box->document().setAnnotatedRegionsDirty(true); + if (box().document().hasAnnotatedRegions()) + box().document().setAnnotatedRegionsDirty(true); } void RenderLayerScrollableArea::setHasVerticalScrollbar(bool hasScrollbar) @@ -819,10 +902,13 @@ void RenderLayerScrollableArea::setHasVerticalScrollbar(bool hasScrollbar) if (hasScrollbar == hasVerticalScrollbar()) return; - if (hasScrollbar) + if (hasScrollbar) { + // Hits in compositing/overflow/automatically-opt-into-composited-scrolling-after-style-change.html + DisableCompositingQueryAsserts disabler; m_vBar = createScrollbar(VerticalScrollbar); - else + } else { destroyScrollbar(VerticalScrollbar); + } // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style. if (m_hBar) @@ -831,8 +917,8 @@ void RenderLayerScrollableArea::setHasVerticalScrollbar(bool hasScrollbar) m_vBar->styleChanged(); // Force an update since we know the scrollbars have changed things. - if (m_box->document().hasAnnotatedRegions()) - m_box->document().setAnnotatedRegionsDirty(true); + if (box().document().hasAnnotatedRegions()) + box().document().setAnnotatedRegionsDirty(true); } int RenderLayerScrollableArea::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const @@ -849,23 +935,12 @@ int RenderLayerScrollableArea::horizontalScrollbarHeight(OverlayScrollbarSizeRel return m_hBar->height(); } -void RenderLayerScrollableArea::positionOverflowControls() -{ - RenderGeometryMap geometryMap(UseTransforms); - RenderView* view = m_box->view(); - if (m_box->layer() != view->layer() && m_box->layer()->parent()) - geometryMap.pushMappingsToAncestor(m_box->layer()->parent(), 0); - - LayoutPoint offsetFromRoot = LayoutPoint(geometryMap.absolutePoint(FloatPoint())); - positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot))); -} - void RenderLayerScrollableArea::positionOverflowControls(const IntSize& offsetFromRoot) { - if (!hasScrollbar() && !m_box->canResize()) + if (!hasScrollbar() && !box().canResize()) return; - const IntRect borderBox = m_box->pixelSnappedBorderBoxRect(); + const IntRect borderBox = box().pixelSnappedBorderBoxRect(); if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) { IntRect vBarRect = rectForVerticalScrollbar(borderBox); vBarRect.move(offsetFromRoot); @@ -888,26 +963,23 @@ void RenderLayerScrollableArea::positionOverflowControls(const IntSize& offsetFr // FIXME, this should eventually be removed, once we are certain that composited // controls get correctly positioned on a compositor update. For now, conservatively // leaving this unchanged. - if (m_box->hasCompositedLayerMapping()) - m_box->compositedLayerMapping()->positionOverflowControlsLayers(offsetFromRoot); -} - -bool RenderLayerScrollableArea::scrollsOverflow() const -{ - if (FrameView* frameView = m_box->view()->frameView()) - return frameView->containsScrollableArea(this); - - return false; + if (box().hasCompositedLayerMapping()) + box().compositedLayerMapping()->positionOverflowControlsLayers(offsetFromRoot); } void RenderLayerScrollableArea::updateScrollCornerStyle() { - RenderObject* actualRenderer = rendererForScrollbar(m_box); - RefPtr<RenderStyle> corner = m_box->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), actualRenderer->style()) : PassRefPtr<RenderStyle>(0); + if (!m_scrollCorner && !hasScrollbar()) + return; + if (!m_scrollCorner && hasOverlayScrollbars()) + return; + + RenderObject* actualRenderer = rendererForScrollbar(box()); + RefPtr<RenderStyle> corner = box().hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), actualRenderer->style()) : PassRefPtr<RenderStyle>(nullptr); if (corner) { if (!m_scrollCorner) { - m_scrollCorner = RenderScrollbarPart::createAnonymous(&m_box->document()); - m_scrollCorner->setParent(m_box); + m_scrollCorner = RenderScrollbarPart::createAnonymous(&box().document()); + m_scrollCorner->setParent(&box()); } m_scrollCorner->setStyle(corner.release()); } else if (m_scrollCorner) { @@ -919,7 +991,7 @@ void RenderLayerScrollableArea::updateScrollCornerStyle() void RenderLayerScrollableArea::paintOverflowControls(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls) { // Don't do anything if we have no overflow. - if (!m_box->hasOverflowClip()) + if (!box().hasOverflowClip()) return; IntPoint adjustedPaintOffset = paintOffset; @@ -947,7 +1019,7 @@ void RenderLayerScrollableArea::paintOverflowControls(GraphicsContext* context, if (!overflowControlsIntersectRect(localDamgeRect)) return; - RenderView* renderView = m_box->view(); + RenderView* renderView = box().view(); RenderLayer* paintingRoot = layer()->enclosingCompositingLayer(); if (!paintingRoot) @@ -1003,22 +1075,22 @@ void RenderLayerScrollableArea::paintScrollCorner(GraphicsContext* context, cons bool RenderLayerScrollableArea::hitTestOverflowControls(HitTestResult& result, const IntPoint& localPoint) { - if (!hasScrollbar() && !m_box->canResize()) + if (!hasScrollbar() && !box().canResize()) return false; IntRect resizeControlRect; - if (m_box->style()->resize() != RESIZE_NONE) { - resizeControlRect = resizerCornerRect(m_box->pixelSnappedBorderBoxRect(), ResizerForPointer); + if (box().style()->resize() != RESIZE_NONE) { + resizeControlRect = resizerCornerRect(box().pixelSnappedBorderBoxRect(), ResizerForPointer); if (resizeControlRect.contains(localPoint)) return true; } int resizeControlSize = max(resizeControlRect.height(), 0); if (m_vBar && m_vBar->shouldParticipateInHitTesting()) { - LayoutRect vBarRect(verticalScrollbarStart(0, m_box->width()), - m_box->borderTop(), + LayoutRect vBarRect(verticalScrollbarStart(0, box().width()), + box().borderTop(), m_vBar->width(), - m_box->height() - (m_box->borderTop() + m_box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize)); + box().height() - (box().borderTop() + box().borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize)); if (vBarRect.contains(localPoint)) { result.setScrollbar(m_vBar.get()); return true; @@ -1028,8 +1100,8 @@ bool RenderLayerScrollableArea::hitTestOverflowControls(HitTestResult& result, c resizeControlSize = max(resizeControlRect.width(), 0); if (m_hBar && m_hBar->shouldParticipateInHitTesting()) { LayoutRect hBarRect(horizontalScrollbarStart(0), - m_box->height() - m_box->borderBottom() - m_hBar->height(), - m_box->width() - (m_box->borderLeft() + m_box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize), + box().height() - box().borderBottom() - m_hBar->height(), + box().width() - (box().borderLeft() + box().borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize), m_hBar->height()); if (hBarRect.contains(localPoint)) { result.setScrollbar(m_hBar.get()); @@ -1044,9 +1116,9 @@ bool RenderLayerScrollableArea::hitTestOverflowControls(HitTestResult& result, c IntRect RenderLayerScrollableArea::resizerCornerRect(const IntRect& bounds, ResizerHitTestType resizerHitTestType) const { - if (m_box->style()->resize() == RESIZE_NONE) + if (box().style()->resize() == RESIZE_NONE) return IntRect(); - IntRect corner = cornerRect(m_box->style(), horizontalScrollbar(), verticalScrollbar(), bounds); + IntRect corner = cornerRect(box().style(), horizontalScrollbar(), verticalScrollbar(), bounds); if (resizerHitTestType == ResizerForTouch) { // We make the resizer virtually larger for touch hit testing. With the @@ -1065,13 +1137,13 @@ IntRect RenderLayerScrollableArea::scrollCornerAndResizerRect() const { IntRect scrollCornerAndResizer = scrollCornerRect(); if (scrollCornerAndResizer.isEmpty()) - scrollCornerAndResizer = resizerCornerRect(m_box->pixelSnappedBorderBoxRect(), ResizerForPointer); + scrollCornerAndResizer = resizerCornerRect(box().pixelSnappedBorderBoxRect(), ResizerForPointer); return scrollCornerAndResizer; } bool RenderLayerScrollableArea::overflowControlsIntersectRect(const IntRect& localRect) const { - const IntRect borderBox = m_box->pixelSnappedBorderBoxRect(); + const IntRect borderBox = box().pixelSnappedBorderBoxRect(); if (rectForHorizontalScrollbar(borderBox).intersects(localRect)) return true; @@ -1090,10 +1162,10 @@ bool RenderLayerScrollableArea::overflowControlsIntersectRect(const IntRect& loc void RenderLayerScrollableArea::paintResizer(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect) { - if (m_box->style()->resize() == RESIZE_NONE) + if (box().style()->resize() == RESIZE_NONE) return; - IntRect absRect = resizerCornerRect(m_box->pixelSnappedBorderBoxRect(), ResizerForPointer); + IntRect absRect = resizerCornerRect(box().pixelSnappedBorderBoxRect(), ResizerForPointer); absRect.moveBy(paintOffset); if (!absRect.intersects(damageRect)) return; @@ -1126,17 +1198,17 @@ void RenderLayerScrollableArea::paintResizer(GraphicsContext* context, const Int bool RenderLayerScrollableArea::isPointInResizeControl(const IntPoint& absolutePoint, ResizerHitTestType resizerHitTestType) const { - if (!m_box->canResize()) + if (!box().canResize()) return false; - IntPoint localPoint = roundedIntPoint(m_box->absoluteToLocal(absolutePoint, UseTransforms)); - IntRect localBounds(0, 0, m_box->pixelSnappedWidth(), m_box->pixelSnappedHeight()); + IntPoint localPoint = roundedIntPoint(box().absoluteToLocal(absolutePoint, UseTransforms)); + IntRect localBounds(0, 0, box().pixelSnappedWidth(), box().pixelSnappedHeight()); return resizerCornerRect(localBounds, resizerHitTestType).contains(localPoint); } bool RenderLayerScrollableArea::hitTestResizerInFragments(const LayerFragments& layerFragments, const HitTestLocation& hitTestLocation) const { - if (!m_box->canResize()) + if (!box().canResize()) return false; if (layerFragments.isEmpty()) @@ -1153,26 +1225,29 @@ bool RenderLayerScrollableArea::hitTestResizerInFragments(const LayerFragments& void RenderLayerScrollableArea::updateResizerAreaSet() { - Frame* frame = m_box->frame(); + LocalFrame* frame = box().frame(); if (!frame) return; FrameView* frameView = frame->view(); if (!frameView) return; - if (m_box->canResize()) - frameView->addResizerArea(m_box); + if (box().canResize()) + frameView->addResizerArea(box()); else - frameView->removeResizerArea(m_box); + frameView->removeResizerArea(box()); } void RenderLayerScrollableArea::updateResizerStyle() { - RenderObject* actualRenderer = rendererForScrollbar(m_box); - RefPtr<RenderStyle> resizer = m_box->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(RESIZER), actualRenderer->style()) : PassRefPtr<RenderStyle>(0); + if (!m_resizer && !box().canResize()) + return; + + RenderObject* actualRenderer = rendererForScrollbar(box()); + RefPtr<RenderStyle> resizer = box().hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(RESIZER), actualRenderer->style()) : PassRefPtr<RenderStyle>(nullptr); if (resizer) { if (!m_resizer) { - m_resizer = RenderScrollbarPart::createAnonymous(&m_box->document()); - m_resizer->setParent(m_box); + m_resizer = RenderScrollbarPart::createAnonymous(&box().document()); + m_resizer->setParent(&box()); } m_resizer->setStyle(resizer.release()); } else if (m_resizer) { @@ -1183,7 +1258,7 @@ void RenderLayerScrollableArea::updateResizerStyle() void RenderLayerScrollableArea::drawPlatformResizerImage(GraphicsContext* context, IntRect resizerCornerRect) { - float deviceScaleFactor = WebCore::deviceScaleFactor(m_box->frame()); + float deviceScaleFactor = WebCore::deviceScaleFactor(box().frame()); RefPtr<Image> resizeCornerImage; IntSize cornerResizerSize; @@ -1198,10 +1273,10 @@ void RenderLayerScrollableArea::drawPlatformResizerImage(GraphicsContext* contex cornerResizerSize = resizeCornerImage->size(); } - if (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) { + if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) { context->save(); context->translate(resizerCornerRect.x() + cornerResizerSize.width(), resizerCornerRect.y() + resizerCornerRect.height() - cornerResizerSize.height()); - context->scale(FloatSize(-1.0, 1.0)); + context->scale(-1.0, 1.0); context->drawImage(resizeCornerImage.get(), IntRect(IntPoint(), cornerResizerSize)); context->restore(); return; @@ -1215,21 +1290,21 @@ IntSize RenderLayerScrollableArea::offsetFromResizeCorner(const IntPoint& absolu // Currently the resize corner is either the bottom right corner or the bottom left corner. // FIXME: This assumes the location is 0, 0. Is this guaranteed to always be the case? IntSize elementSize = layer()->size(); - if (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) + if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) elementSize.setWidth(0); IntPoint resizerPoint = IntPoint(elementSize); - IntPoint localPoint = roundedIntPoint(m_box->absoluteToLocal(absolutePoint, UseTransforms)); + IntPoint localPoint = roundedIntPoint(box().absoluteToLocal(absolutePoint, UseTransforms)); return localPoint - resizerPoint; } void RenderLayerScrollableArea::resize(const PlatformEvent& evt, const LayoutSize& oldOffset) { // FIXME: This should be possible on generated content but is not right now. - if (!inResizeMode() || !m_box->canResize() || !m_box->node()) + if (!inResizeMode() || !box().canResize() || !box().node()) return; - ASSERT(m_box->node()->isElementNode()); - Element* element = toElement(m_box->node()); + ASSERT(box().node()->isElementNode()); + Element* element = toElement(box().node()); Document& document = element->document(); @@ -1253,34 +1328,34 @@ void RenderLayerScrollableArea::resize(const PlatformEvent& evt, const LayoutSiz ASSERT_NOT_REACHED(); } - float zoomFactor = m_box->style()->effectiveZoom(); + float zoomFactor = box().style()->effectiveZoom(); LayoutSize newOffset = offsetFromResizeCorner(document.view()->windowToContents(pos)); newOffset.setWidth(newOffset.width() / zoomFactor); newOffset.setHeight(newOffset.height() / zoomFactor); - LayoutSize currentSize = LayoutSize(m_box->width() / zoomFactor, m_box->height() / zoomFactor); + LayoutSize currentSize = LayoutSize(box().width() / zoomFactor, box().height() / zoomFactor); LayoutSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize); element->setMinimumSizeForResizing(minimumSize); LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor); - if (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) { + if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) { newOffset.setWidth(-newOffset.width()); adjustedOldOffset.setWidth(-adjustedOldOffset.width()); } LayoutSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize; - bool isBoxSizingBorder = m_box->style()->boxSizing() == BORDER_BOX; + bool isBoxSizingBorder = box().style()->boxSizing() == BORDER_BOX; - EResize resize = m_box->style()->resize(); + EResize resize = box().style()->resize(); if (resize != RESIZE_VERTICAL && difference.width()) { if (element->isFormControlElement()) { // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>). - element->setInlineStyleProperty(CSSPropertyMarginLeft, m_box->marginLeft() / zoomFactor, CSSPrimitiveValue::CSS_PX); - element->setInlineStyleProperty(CSSPropertyMarginRight, m_box->marginRight() / zoomFactor, CSSPrimitiveValue::CSS_PX); + element->setInlineStyleProperty(CSSPropertyMarginLeft, box().marginLeft() / zoomFactor, CSSPrimitiveValue::CSS_PX); + element->setInlineStyleProperty(CSSPropertyMarginRight, box().marginRight() / zoomFactor, CSSPrimitiveValue::CSS_PX); } - LayoutUnit baseWidth = m_box->width() - (isBoxSizingBorder ? LayoutUnit() : m_box->borderAndPaddingWidth()); + LayoutUnit baseWidth = box().width() - (isBoxSizingBorder ? LayoutUnit() : box().borderAndPaddingWidth()); baseWidth = baseWidth / zoomFactor; element->setInlineStyleProperty(CSSPropertyWidth, roundToInt(baseWidth + difference.width()), CSSPrimitiveValue::CSS_PX); } @@ -1288,10 +1363,10 @@ void RenderLayerScrollableArea::resize(const PlatformEvent& evt, const LayoutSiz if (resize != RESIZE_HORIZONTAL && difference.height()) { if (element->isFormControlElement()) { // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>). - element->setInlineStyleProperty(CSSPropertyMarginTop, m_box->marginTop() / zoomFactor, CSSPrimitiveValue::CSS_PX); - element->setInlineStyleProperty(CSSPropertyMarginBottom, m_box->marginBottom() / zoomFactor, CSSPrimitiveValue::CSS_PX); + element->setInlineStyleProperty(CSSPropertyMarginTop, box().marginTop() / zoomFactor, CSSPrimitiveValue::CSS_PX); + element->setInlineStyleProperty(CSSPropertyMarginBottom, box().marginBottom() / zoomFactor, CSSPrimitiveValue::CSS_PX); } - LayoutUnit baseHeight = m_box->height() - (isBoxSizingBorder ? LayoutUnit() : m_box->borderAndPaddingHeight()); + LayoutUnit baseHeight = box().height() - (isBoxSizingBorder ? LayoutUnit() : box().borderAndPaddingHeight()); baseHeight = baseHeight / zoomFactor; element->setInlineStyleProperty(CSSPropertyHeight, roundToInt(baseHeight + difference.height()), CSSPrimitiveValue::CSS_PX); } @@ -1303,8 +1378,8 @@ void RenderLayerScrollableArea::resize(const PlatformEvent& evt, const LayoutSiz LayoutRect RenderLayerScrollableArea::exposeRect(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY) { - LayoutRect localExposeRect(m_box->absoluteToLocalQuad(FloatQuad(FloatRect(rect)), UseTransforms).boundingBox()); - LayoutRect layerBounds(0, 0, m_box->clientWidth(), m_box->clientHeight()); + LayoutRect localExposeRect(box().absoluteToLocalQuad(FloatQuad(FloatRect(rect)), UseTransforms).boundingBox()); + LayoutRect layerBounds(0, 0, box().clientWidth(), box().clientHeight()); LayoutRect r = ScrollAlignment::getRectToExpose(layerBounds, localExposeRect, alignX, alignY); IntSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset() + toIntSize(roundedIntRect(r).location())); @@ -1315,12 +1390,12 @@ LayoutRect RenderLayerScrollableArea::exposeRect(const LayoutRect& rect, const S scrollToOffset(clampedScrollOffset); IntSize scrollOffsetDifference = adjustedScrollOffset() - oldScrollOffset; localExposeRect.move(-scrollOffsetDifference); - return LayoutRect(m_box->localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox()); + return LayoutRect(box().localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox()); } void RenderLayerScrollableArea::updateScrollableAreaSet(bool hasOverflow) { - Frame* frame = m_box->frame(); + LocalFrame* frame = box().frame(); if (!frame) return; @@ -1328,148 +1403,58 @@ void RenderLayerScrollableArea::updateScrollableAreaSet(bool hasOverflow) if (!frameView) return; - bool isVisibleToHitTest = m_box->visibleToHitTesting(); - if (HTMLFrameOwnerElement* owner = frame->ownerElement()) + // FIXME: Does this need to be fixed later for OOPI? + bool isVisibleToHitTest = box().visibleToHitTesting(); + if (HTMLFrameOwnerElement* owner = frame->deprecatedLocalOwner()) isVisibleToHitTest &= owner->renderer() && owner->renderer()->visibleToHitTesting(); - bool requiresScrollableArea = hasOverflow && isVisibleToHitTest; - bool updatedScrollableAreaSet = false; - if (requiresScrollableArea) { - if (frameView->addScrollableArea(this)) - updatedScrollableAreaSet = true; - } else { - if (frameView->removeScrollableArea(this)) - updatedScrollableAreaSet = true; - } - - if (updatedScrollableAreaSet) { - // Count the total number of RenderLayers that are scrollable areas for - // any period. We only want to record this at most once per RenderLayer. - if (requiresScrollableArea && !m_isScrollableAreaHasBeenRecorded) { - blink::Platform::current()->histogramEnumeration("Renderer.CompositedScrolling", RenderLayer::IsScrollableAreaBucket, RenderLayer::CompositedScrollingHistogramMax); - m_isScrollableAreaHasBeenRecorded = true; - } - - // We always want composited scrolling if compositor driven accelerated - // scrolling is enabled. Since we will not update needs composited scrolling - // in this case, we must force our state to update. - if (layer()->compositorDrivenAcceleratedScrollingEnabled()) - layer()->didUpdateNeedsCompositedScrolling(); - else if (requiresScrollableArea) - m_box->view()->compositor()->setNeedsUpdateCompositingRequirementsState(); - else - setNeedsCompositedScrolling(false); - } -} - -void RenderLayerScrollableArea::updateNeedsCompositedScrolling() -{ - TRACE_EVENT0("comp-scroll", "RenderLayer::updateNeedsCompositedScrolling"); - - layer()->stackingNode()->updateDescendantsAreContiguousInStackingOrder(); - layer()->updateDescendantDependentFlags(); - - ASSERT(scrollsOverflow()); - const bool needsToBeStackingContainer = layer()->acceleratedCompositingForOverflowScrollEnabled() - && layer()->stackingNode()->descendantsAreContiguousInStackingOrder() - && !layer()->hasUnclippedDescendant(); + bool didNeedCompositedScrolling = needsCompositedScrolling(); - const bool needsToBeStackingContainerDidChange = layer()->stackingNode()->setNeedsToBeStackingContainer(needsToBeStackingContainer); + bool didScrollOverflow = m_scrollsOverflow; - const bool needsCompositedScrolling = needsToBeStackingContainer - || layer()->compositorDrivenAcceleratedScrollingEnabled(); - - // We gather a boolean value for use with Google UMA histograms to - // quantify the actual effects of a set of patches attempting to - // relax composited scrolling requirements, thereby increasing the - // number of composited overflow divs. - if (layer()->acceleratedCompositingForOverflowScrollEnabled()) - blink::Platform::current()->histogramEnumeration("Renderer.NeedsCompositedScrolling", needsCompositedScrolling, 2); + m_scrollsOverflow = hasOverflow && isVisibleToHitTest; + if (didScrollOverflow == scrollsOverflow()) + return; - const bool needsCompositedScrollingDidChange = setNeedsCompositedScrolling(needsCompositedScrolling); + if (m_scrollsOverflow) + frameView->addScrollableArea(this); + else + frameView->removeScrollableArea(this); - if (needsToBeStackingContainerDidChange || needsCompositedScrollingDidChange) { - // Note, the z-order lists may need to be rebuilt, but our code guarantees - // that we have not affected stacking, so we will not dirty - // m_descendantsAreContiguousInStackingOrder for either us or our stacking - // context or container. + if (didNeedCompositedScrolling != needsCompositedScrolling()) layer()->didUpdateNeedsCompositedScrolling(); - } -} - -bool RenderLayerScrollableArea::setNeedsCompositedScrolling(bool needsCompositedScrolling) -{ - if (this->needsCompositedScrolling() == needsCompositedScrolling) - return false; - - // Count the total number of RenderLayers which need composited scrolling at - // some point. This should be recorded at most once per RenderLayer, so we - // check m_willUseCompositedScrollingHasBeenRecorded. - if (layer()->acceleratedCompositingForOverflowScrollEnabled() && !m_willUseCompositedScrollingHasBeenRecorded) { - blink::Platform::current()->histogramEnumeration("Renderer.CompositedScrolling", RenderLayer::WillUseCompositedScrollingBucket, RenderLayer::CompositedScrollingHistogramMax); - m_willUseCompositedScrollingHasBeenRecorded = true; - } - - m_needsCompositedScrolling = needsCompositedScrolling; - - return true; -} - -void RenderLayerScrollableArea::updateHasVisibleNonLayerContent() -{ - layer()->updateHasVisibleNonLayerContent(); } void RenderLayerScrollableArea::updateCompositingLayersAfterScroll() { - RenderLayerCompositor* compositor = m_box->view()->compositor(); + RenderLayerCompositor* compositor = box().view()->compositor(); if (compositor->inCompositingMode()) { - // FIXME: Our stacking container is guaranteed to contain all of our descendants that may need - // repositioning, so we should be able to enqueue a partial update compositing layers from there. - // this feature was overridden for now by deferred compositing updates. - if (usesCompositedScrolling()) - compositor->updateCompositingLayers(CompositingUpdateOnCompositedScroll); - else - compositor->updateCompositingLayers(CompositingUpdateOnScroll); + if (usesCompositedScrolling()) { + DisableCompositingQueryAsserts disabler; + ASSERT(box().hasCompositedLayerMapping()); + box().compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree); + compositor->setNeedsCompositingUpdate(CompositingUpdateAfterGeometryChange); + } else { + layer()->setNeedsCompositingInputsUpdate(); + compositor->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange); + } } } bool RenderLayerScrollableArea::usesCompositedScrolling() const { // Scroll form controls on the main thread so they exhibit correct touch scroll event bubbling - if (m_box && (m_box->isIntristicallyScrollable(VerticalScrollbar) || m_box->isIntristicallyScrollable(HorizontalScrollbar))) + if (box().isIntristicallyScrollable(VerticalScrollbar) || box().isIntristicallyScrollable(HorizontalScrollbar)) return false; - return m_box->hasCompositedLayerMapping() && m_box->compositedLayerMapping()->scrollingLayer(); -} - -bool RenderLayerScrollableArea::adjustForForceCompositedScrollingMode(bool value) const -{ - switch (m_forceNeedsCompositedScrolling) { - case DoNotForceCompositedScrolling: - return value; - case CompositedScrollingAlwaysOn: - return true; - case CompositedScrollingAlwaysOff: - return false; - } - - ASSERT_NOT_REACHED(); - return value; + // See https://codereview.chromium.org/176633003/ for the tests that fail without this disabler. + DisableCompositingQueryAsserts disabler; + return box().hasCompositedLayerMapping() && box().compositedLayerMapping()->scrollingLayer(); } bool RenderLayerScrollableArea::needsCompositedScrolling() const { - return adjustForForceCompositedScrollingMode(m_needsCompositedScrolling); -} - -void RenderLayerScrollableArea::setForceNeedsCompositedScrolling(ForceNeedsCompositedScrollingMode mode) -{ - if (m_forceNeedsCompositedScrolling == mode) - return; - - m_forceNeedsCompositedScrolling = mode; - layer()->didUpdateNeedsCompositedScrolling(); + return scrollsOverflow() && box().view()->compositor()->acceleratedCompositingForOverflowScrollEnabled(); } } // Namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerScrollableArea.h b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerScrollableArea.h index 0444ca78b33..a41bbde5232 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerScrollableArea.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerScrollableArea.h @@ -53,12 +53,6 @@ enum ResizerHitTestType { ResizerForTouch }; -enum ForceNeedsCompositedScrollingMode { - DoNotForceCompositedScrolling = 0, - CompositedScrollingAlwaysOn = 1, - CompositedScrollingAlwaysOff = 2 -}; - class PlatformEvent; class RenderBox; class RenderLayer; @@ -68,7 +62,9 @@ class RenderLayerScrollableArea FINAL : public ScrollableArea { friend class Internals; public: - RenderLayerScrollableArea(RenderBox*); + // FIXME: We should pass in the RenderBox but this opens a window + // for crashers during RenderLayer setup (see crbug.com/368062). + RenderLayerScrollableArea(RenderLayer&); virtual ~RenderLayerScrollableArea(); bool hasHorizontalScrollbar() const { return horizontalScrollbar(); } @@ -76,7 +72,6 @@ public: virtual Scrollbar* horizontalScrollbar() const OVERRIDE { return m_hBar.get(); } virtual Scrollbar* verticalScrollbar() const OVERRIDE { return m_vBar.get(); } - virtual ScrollableArea* enclosingScrollableArea() const OVERRIDE; virtual GraphicsLayer* layerForScrolling() const OVERRIDE; virtual GraphicsLayer* layerForHorizontalScrollbar() const OVERRIDE; @@ -124,6 +119,9 @@ public: void updateAfterLayout(); void updateAfterStyleChange(const RenderStyle*); + void updateAfterOverflowRecalc(); + + virtual void updateAfterCompositingChange() OVERRIDE; bool hasScrollbar() const { return m_hBar || m_vBar; } @@ -141,8 +139,8 @@ public: return resizerCornerRect(bounds, ResizerForTouch); } - int scrollWidth() const; - int scrollHeight() const; + LayoutUnit scrollWidth() const; + LayoutUnit scrollHeight() const; int verticalScrollbarWidth(OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; int horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; @@ -153,9 +151,6 @@ public: void paintOverflowControls(GraphicsContext*, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls); void paintScrollCorner(GraphicsContext*, const IntPoint&, const IntRect& damageRect); - // If IntSize is not given, then we must incur additional overhead to instantiate a RenderGeometryMap - // and compute the correct offset ourselves. - void positionOverflowControls(); void positionOverflowControls(const IntSize& offsetFromRoot); // isPointInResizeControl() is used for testing if a pointer/touch position is in the resize control @@ -167,7 +162,10 @@ public: LayoutRect exposeRect(const LayoutRect&, const ScrollAlignment& alignX, const ScrollAlignment& alignY); - bool scrollsOverflow() const; + // Returns true our scrollable area is in the FrameView's collection of scrollable areas. This can + // only happen if we're both scrollable, and we do in fact overflow. This means that overflow: hidden + // layers never get added to the FrameView's collection. + bool scrollsOverflow() const { return m_scrollsOverflow; } // Rectangle encompassing the scroll corner and resizer rect. IntRect scrollCornerAndResizerRect() const; @@ -211,33 +209,22 @@ private: void updateResizerStyle(); void drawPlatformResizerImage(GraphicsContext*, IntRect resizerCornerRect); + RenderBox& box() const; RenderLayer* layer() const; void updateScrollableAreaSet(bool hasOverflow); void updateCompositingLayersAfterScroll(); - virtual void updateNeedsCompositedScrolling() OVERRIDE; - bool setNeedsCompositedScrolling(bool); - - virtual void updateHasVisibleNonLayerContent() OVERRIDE; - void setForceNeedsCompositedScrolling(ForceNeedsCompositedScrollingMode); - - RenderBox* m_box; + RenderLayer& m_layer; // Keeps track of whether the layer is currently resizing, so events can cause resizing to start and stop. unsigned m_inResizeMode : 1; + unsigned m_scrollsOverflow : 1; unsigned m_scrollDimensionsDirty : 1; unsigned m_inOverflowRelayout : 1; - unsigned m_needsCompositedScrolling : 1; - unsigned m_willUseCompositedScrollingHasBeenRecorded : 1; - - unsigned m_isScrollableAreaHasBeenRecorded : 1; - - ForceNeedsCompositedScrollingMode m_forceNeedsCompositedScrolling; - // The width/height of our scrolled area. LayoutRect m_overflowRect; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerStackingNode.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerStackingNode.cpp index 715dcecfe77..eaa6dfc09b4 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerStackingNode.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerStackingNode.cpp @@ -45,37 +45,33 @@ #include "core/rendering/RenderLayerStackingNode.h" #include "core/rendering/RenderLayer.h" -#include "core/rendering/RenderLayerCompositor.h" #include "core/rendering/RenderView.h" +#include "core/rendering/compositing/RenderLayerCompositor.h" #include "public/platform/Platform.h" namespace WebCore { // FIXME: This should not require RenderLayer. There is currently a cycle where -// in order to determine if we shoulBeNormalFlowOnly() and isStackingContainer() -// we have to ask the render layer about some of its state. +// in order to determine if we shoulBeNormalFlowOnly() we have to ask the render +// layer about some of its state. RenderLayerStackingNode::RenderLayerStackingNode(RenderLayer* layer) : m_layer(layer) - , m_descendantsAreContiguousInStackingOrder(false) - , m_descendantsAreContiguousInStackingOrderDirty(true) , m_normalFlowListDirty(true) - , m_needsToBeStackingContainer(false) - , m_needsToBeStackingContainerHasBeenRecorded(false) -#if !ASSERT_DISABLED +#if ASSERT_ENABLED , m_layerListMutationAllowed(true) , m_stackingParent(0) #endif { m_isNormalFlowOnly = shouldBeNormalFlowOnly(); - // Non-stacking containers should have empty z-order lists. As this is already the case, + // Non-stacking contexts should have empty z-order lists. As this is already the case, // there is no need to dirty / recompute these lists. - m_zOrderListsDirty = isStackingContainer(); + m_zOrderListsDirty = isStackingContext(); } RenderLayerStackingNode::~RenderLayerStackingNode() { -#if !ASSERT_DISABLED +#if ASSERT_ENABLED if (!renderer()->documentBeingDestroyed()) { ASSERT(!isInStackingParentZOrderLists()); ASSERT(!isInStackingParentNormalFlowList()); @@ -86,11 +82,6 @@ RenderLayerStackingNode::~RenderLayerStackingNode() #endif } -bool RenderLayerStackingNode::isStackingContext(const RenderStyle* style) const -{ - return !style->hasAutoZIndex() || layer()->isRootLayer(); -} - // Helper for the sorting of layers by z-index. static inline bool compareZIndex(RenderLayerStackingNode* first, RenderLayerStackingNode* second) { @@ -99,47 +90,16 @@ static inline bool compareZIndex(RenderLayerStackingNode* first, RenderLayerStac RenderLayerCompositor* RenderLayerStackingNode::compositor() const { - if (!renderer()->view()) - return 0; + ASSERT(renderer()->view()); return renderer()->view()->compositor(); } -void RenderLayerStackingNode::dirtyNormalFlowListCanBePromotedToStackingContainer() -{ - m_descendantsAreContiguousInStackingOrderDirty = true; - - if (m_normalFlowListDirty || !normalFlowList()) - return; - - for (size_t index = 0; index < normalFlowList()->size(); ++index) - normalFlowList()->at(index)->dirtyNormalFlowListCanBePromotedToStackingContainer(); -} - -void RenderLayerStackingNode::dirtySiblingStackingNodeCanBePromotedToStackingContainer() -{ - RenderLayerStackingNode* stackingNode = ancestorStackingNode(); - if (!stackingNode) - return; - - if (!stackingNode->zOrderListsDirty() && stackingNode->posZOrderList()) { - for (size_t index = 0; index < stackingNode->posZOrderList()->size(); ++index) - stackingNode->posZOrderList()->at(index)->setDescendantsAreContiguousInStackingOrderDirty(true); - } - - stackingNode->dirtyNormalFlowListCanBePromotedToStackingContainer(); - - if (!stackingNode->zOrderListsDirty() && stackingNode->negZOrderList()) { - for (size_t index = 0; index < stackingNode->negZOrderList()->size(); ++index) - stackingNode->negZOrderList()->at(index)->setDescendantsAreContiguousInStackingOrderDirty(true); - } -} - void RenderLayerStackingNode::dirtyZOrderLists() { ASSERT(m_layerListMutationAllowed); - ASSERT(isStackingContainer()); + ASSERT(isStackingContext()); -#if !ASSERT_DISABLED +#if ASSERT_ENABLED updateStackingParentForZOrderLists(0); #endif @@ -149,35 +109,13 @@ void RenderLayerStackingNode::dirtyZOrderLists() m_negZOrderList->clear(); m_zOrderListsDirty = true; - m_descendantsAreContiguousInStackingOrderDirty = true; - - if (!renderer()->documentBeingDestroyed()) { - compositor()->setNeedsUpdateCompositingRequirementsState(); - compositor()->setCompositingLayersNeedRebuild(); - if (layer()->acceleratedCompositingForOverflowScrollEnabled()) - compositor()->setNeedsToRecomputeCompositingRequirements(); - } + if (!renderer()->documentBeingDestroyed()) + compositor()->setNeedsCompositingUpdate(CompositingUpdateRebuildTree); } -void RenderLayerStackingNode::dirtyStackingContainerZOrderLists() +void RenderLayerStackingNode::dirtyStackingContextZOrderLists() { - // Any siblings in the ancestor stacking context could also be affected. - // Changing z-index, for example, could cause us to stack in between a - // sibling's descendants, meaning that we have to recompute - // m_descendantsAreContiguousInStackingOrder for that sibling. - dirtySiblingStackingNodeCanBePromotedToStackingContainer(); - - RenderLayerStackingNode* stackingContainerNode = ancestorStackingContainerNode(); - if (stackingContainerNode) - stackingContainerNode->dirtyZOrderLists(); - - // Any change that could affect our stacking container's z-order list could - // cause other RenderLayers in our stacking context to either opt in or out - // of composited scrolling. It is important that we make our stacking - // context aware of these z-order changes so the appropriate updating can - // happen. - RenderLayerStackingNode* stackingNode = ancestorStackingNode(); - if (stackingNode && stackingNode != stackingContainerNode) + if (RenderLayerStackingNode* stackingNode = ancestorStackingContextNode()) stackingNode->dirtyZOrderLists(); } @@ -185,7 +123,7 @@ void RenderLayerStackingNode::dirtyNormalFlowList() { ASSERT(m_layerListMutationAllowed); -#if !ASSERT_DISABLED +#if ASSERT_ENABLED updateStackingParentForNormalFlowList(0); #endif @@ -193,57 +131,48 @@ void RenderLayerStackingNode::dirtyNormalFlowList() m_normalFlowList->clear(); m_normalFlowListDirty = true; - if (!renderer()->documentBeingDestroyed()) { - compositor()->setCompositingLayersNeedRebuild(); - if (layer()->acceleratedCompositingForOverflowScrollEnabled()) - compositor()->setNeedsToRecomputeCompositingRequirements(); - } + if (!renderer()->documentBeingDestroyed()) + compositor()->setNeedsCompositingUpdate(CompositingUpdateRebuildTree); } void RenderLayerStackingNode::rebuildZOrderLists() { ASSERT(m_layerListMutationAllowed); - ASSERT(isDirtyStackingContainer()); - rebuildZOrderLists(m_posZOrderList, m_negZOrderList); - -#if !ASSERT_DISABLED - updateStackingParentForZOrderLists(this); -#endif - - m_zOrderListsDirty = false; -} + ASSERT(isDirtyStackingContext()); -void RenderLayerStackingNode::rebuildZOrderLists(OwnPtr<Vector<RenderLayerStackingNode*> >& posZOrderList, - OwnPtr<Vector<RenderLayerStackingNode*> >& negZOrderList, const RenderLayerStackingNode* nodeToForceAsStackingContainer, - CollectLayersBehavior collectLayersBehavior) -{ for (RenderLayer* child = layer()->firstChild(); child; child = child->nextSibling()) { if (!layer()->reflectionInfo() || layer()->reflectionInfo()->reflectionLayer() != child) - child->stackingNode()->collectLayers(posZOrderList, negZOrderList, nodeToForceAsStackingContainer, collectLayersBehavior); + child->stackingNode()->collectLayers(m_posZOrderList, m_negZOrderList); } // Sort the two lists. - if (posZOrderList) - std::stable_sort(posZOrderList->begin(), posZOrderList->end(), compareZIndex); + if (m_posZOrderList) + std::stable_sort(m_posZOrderList->begin(), m_posZOrderList->end(), compareZIndex); - if (negZOrderList) - std::stable_sort(negZOrderList->begin(), negZOrderList->end(), compareZIndex); + if (m_negZOrderList) + std::stable_sort(m_negZOrderList->begin(), m_negZOrderList->end(), compareZIndex); // Append layers for top layer elements after normal layer collection, to ensure they are on top regardless of z-indexes. // The renderers of top layer elements are children of the view, sorted in top layer stacking order. if (layer()->isRootLayer()) { - RenderObject* view = renderer()->view(); + RenderView* view = renderer()->view(); for (RenderObject* child = view->firstChild(); child; child = child->nextSibling()) { Element* childElement = (child->node() && child->node()->isElementNode()) ? toElement(child->node()) : 0; if (childElement && childElement->isInTopLayer()) { RenderLayer* layer = toRenderLayerModelObject(child)->layer(); // Create the buffer if it doesn't exist yet. - if (!posZOrderList) - posZOrderList = adoptPtr(new Vector<RenderLayerStackingNode*>); - posZOrderList->append(layer->stackingNode()); + if (!m_posZOrderList) + m_posZOrderList = adoptPtr(new Vector<RenderLayerStackingNode*>); + m_posZOrderList->append(layer->stackingNode()); } } } + +#if ASSERT_ENABLED + updateStackingParentForZOrderLists(this); +#endif + + m_zOrderListsDirty = false; } void RenderLayerStackingNode::updateNormalFlowList() @@ -254,7 +183,6 @@ void RenderLayerStackingNode::updateNormalFlowList() ASSERT(m_layerListMutationAllowed); for (RenderLayer* child = layer()->firstChild(); child; child = child->nextSibling()) { - // Ignore non-overflow layers and reflections. if (child->stackingNode()->isNormalFlowOnly() && (!layer()->reflectionInfo() || layer()->reflectionInfo()->reflectionLayer() != child)) { if (!m_normalFlowList) m_normalFlowList = adoptPtr(new Vector<RenderLayerStackingNode*>); @@ -262,71 +190,36 @@ void RenderLayerStackingNode::updateNormalFlowList() } } -#if !ASSERT_DISABLED +#if ASSERT_ENABLED updateStackingParentForNormalFlowList(this); #endif m_normalFlowListDirty = false; } -void RenderLayerStackingNode::collectLayers(OwnPtr<Vector<RenderLayerStackingNode*> >& posBuffer, OwnPtr<Vector<RenderLayerStackingNode*> >& negBuffer, - const RenderLayerStackingNode* nodeToForceAsStackingContainer, CollectLayersBehavior collectLayersBehavior) +void RenderLayerStackingNode::collectLayers(OwnPtr<Vector<RenderLayerStackingNode*> >& posBuffer, OwnPtr<Vector<RenderLayerStackingNode*> >& negBuffer) { if (layer()->isInTopLayer()) return; layer()->updateDescendantDependentFlags(); - bool isStacking = false; - bool isNormalFlow = false; - - switch (collectLayersBehavior) { - case ForceLayerToStackingContainer: - ASSERT(nodeToForceAsStackingContainer); - if (this == nodeToForceAsStackingContainer) { - isStacking = true; - isNormalFlow = false; - } else { - isStacking = isStackingContext(); - isNormalFlow = shouldBeNormalFlowOnlyIgnoringCompositedScrolling(); - } - break; - case OverflowScrollCanBeStackingContainers: - ASSERT(!nodeToForceAsStackingContainer); - isStacking = isStackingContainer(); - isNormalFlow = isNormalFlowOnly(); - break; - case OnlyStackingContextsCanBeStackingContainers: - isStacking = isStackingContext(); - isNormalFlow = shouldBeNormalFlowOnlyIgnoringCompositedScrolling(); - break; - } - - // Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists. - if (!isNormalFlow && !layer()->isOutOfFlowRenderFlowThread()) { - // Determine which buffer the child should be in. + if (!isNormalFlowOnly()) { OwnPtr<Vector<RenderLayerStackingNode*> >& buffer = (zIndex() >= 0) ? posBuffer : negBuffer; - - // Create the buffer if it doesn't exist yet. if (!buffer) buffer = adoptPtr(new Vector<RenderLayerStackingNode*>); - - // Append ourselves at the end of the appropriate buffer. buffer->append(this); } - // Recur into our children to collect more layers, but only if we don't establish - // a stacking context/container. - if (!isStacking) { + if (!isStackingContext()) { for (RenderLayer* child = layer()->firstChild(); child; child = child->nextSibling()) { - // Ignore reflections. if (!layer()->reflectionInfo() || layer()->reflectionInfo()->reflectionLayer() != child) - child->stackingNode()->collectLayers(posBuffer, negBuffer, nodeToForceAsStackingContainer, collectLayersBehavior); + child->stackingNode()->collectLayers(posBuffer, negBuffer); } } } -#if !ASSERT_DISABLED +#if ASSERT_ENABLED bool RenderLayerStackingNode::isInStackingParentZOrderLists() const { if (!m_stackingParent || m_stackingParent->zOrderListsDirty()) @@ -386,50 +279,26 @@ void RenderLayerStackingNode::updateLayerListsIfNeeded() void RenderLayerStackingNode::updateStackingNodesAfterStyleChange(const RenderStyle* oldStyle) { - bool wasStackingContext = oldStyle ? isStackingContext(oldStyle) : false; - EVisibility oldVisibility = oldStyle ? oldStyle->visibility() : VISIBLE; + bool wasStackingContext = oldStyle ? !oldStyle->hasAutoZIndex() : false; int oldZIndex = oldStyle ? oldStyle->zIndex() : 0; - // FIXME: RenderLayer already handles visibility changes through our visiblity dirty bits. This logic could - // likely be folded along with the rest. bool isStackingContext = this->isStackingContext(); - if (isStackingContext == wasStackingContext && oldVisibility == renderer()->style()->visibility() && oldZIndex == zIndex()) + if (isStackingContext == wasStackingContext && oldZIndex == zIndex()) return; - dirtyStackingContainerZOrderLists(); + dirtyStackingContextZOrderLists(); - if (isStackingContainer()) + if (isStackingContext) dirtyZOrderLists(); else clearZOrderLists(); - - compositor()->setNeedsUpdateCompositingRequirementsState(); } +// FIXME: Rename shouldBeNormalFlowOnly to something more accurate now that CSS +// 2.1 defines the term "normal flow". bool RenderLayerStackingNode::shouldBeNormalFlowOnly() const { - return shouldBeNormalFlowOnlyIgnoringCompositedScrolling() && !layer()->needsCompositedScrolling(); -} - -bool RenderLayerStackingNode::shouldBeNormalFlowOnlyIgnoringCompositedScrolling() const -{ - const bool couldBeNormalFlow = renderer()->hasOverflowClip() - || renderer()->hasReflection() - || renderer()->hasMask() - || renderer()->isCanvas() - || renderer()->isVideo() - || renderer()->isEmbeddedObject() - || renderer()->isRenderIFrame() - || (renderer()->style()->specifiesColumns() && !layer()->isRootLayer()); - const bool preventsElementFromBeingNormalFlow = renderer()->isPositioned() - || renderer()->hasTransform() - || renderer()->hasClipPath() - || renderer()->hasFilter() - || renderer()->hasBlendMode() - || layer()->isTransparent() - || renderer()->style()->hasFlowFrom(); - - return couldBeNormalFlow && !preventsElementFromBeingNormalFlow; + return !isStackingContext() && !renderer()->isPositioned(); } void RenderLayerStackingNode::updateIsNormalFlowOnly() @@ -441,215 +310,16 @@ void RenderLayerStackingNode::updateIsNormalFlowOnly() m_isNormalFlowOnly = isNormalFlowOnly; if (RenderLayer* p = layer()->parent()) p->stackingNode()->dirtyNormalFlowList(); - dirtyStackingContainerZOrderLists(); -} - -bool RenderLayerStackingNode::needsToBeStackingContainer() const -{ - return layer()->scrollableArea() && layer()->scrollableArea()->adjustForForceCompositedScrollingMode(m_needsToBeStackingContainer); -} - -// Determine whether the current layer can be promoted to a stacking container. -// We do this by computing what positive and negative z-order lists would look -// like before and after promotion, and ensuring that proper stacking order is -// preserved between the two sets of lists. -void RenderLayerStackingNode::updateDescendantsAreContiguousInStackingOrder() -{ - TRACE_EVENT0("blink_rendering,comp-scroll", "RenderLayerStackingNode::updateDescendantsAreContiguousInStackingOrder"); - - const RenderLayer* currentLayer = layer(); - if (isStackingContext() || !m_descendantsAreContiguousInStackingOrderDirty || !currentLayer->acceleratedCompositingForOverflowScrollEnabled()) - return; - - if (!currentLayer->scrollsOverflow()) - return; - - RenderLayerStackingNode* stackingNode = ancestorStackingNode(); - if (!stackingNode) - return; - - OwnPtr<Vector<RenderLayerStackingNode*> > posZOrderListBeforePromote = adoptPtr(new Vector<RenderLayerStackingNode*>); - OwnPtr<Vector<RenderLayerStackingNode*> > negZOrderListBeforePromote = adoptPtr(new Vector<RenderLayerStackingNode*>); - OwnPtr<Vector<RenderLayerStackingNode*> > posZOrderListAfterPromote = adoptPtr(new Vector<RenderLayerStackingNode*>); - OwnPtr<Vector<RenderLayerStackingNode*> > negZOrderListAfterPromote = adoptPtr(new Vector<RenderLayerStackingNode*>); - - collectBeforePromotionZOrderList(stackingNode, posZOrderListBeforePromote, negZOrderListBeforePromote); - collectAfterPromotionZOrderList(stackingNode, posZOrderListAfterPromote, negZOrderListAfterPromote); - - size_t maxIndex = std::min(posZOrderListAfterPromote->size() + negZOrderListAfterPromote->size(), posZOrderListBeforePromote->size() + negZOrderListBeforePromote->size()); - - m_descendantsAreContiguousInStackingOrderDirty = false; - m_descendantsAreContiguousInStackingOrder = false; - - const RenderLayerStackingNode* nodeAfterPromote = 0; - for (size_t i = 0; i < maxIndex && nodeAfterPromote != this; ++i) { - const RenderLayerStackingNode* nodeBeforePromote = i < negZOrderListBeforePromote->size() - ? negZOrderListBeforePromote->at(i) - : posZOrderListBeforePromote->at(i - negZOrderListBeforePromote->size()); - nodeAfterPromote = i < negZOrderListAfterPromote->size() - ? negZOrderListAfterPromote->at(i) - : posZOrderListAfterPromote->at(i - negZOrderListAfterPromote->size()); - - if (nodeBeforePromote != nodeAfterPromote && (nodeAfterPromote != this || renderer()->hasBackground())) - return; - } - - nodeAfterPromote = 0; - for (size_t i = 0; i < maxIndex && nodeAfterPromote != this; ++i) { - const RenderLayerStackingNode* nodeBeforePromote = i < posZOrderListBeforePromote->size() - ? posZOrderListBeforePromote->at(posZOrderListBeforePromote->size() - i - 1) - : negZOrderListBeforePromote->at(negZOrderListBeforePromote->size() + posZOrderListBeforePromote->size() - i - 1); - nodeAfterPromote = i < posZOrderListAfterPromote->size() - ? posZOrderListAfterPromote->at(posZOrderListAfterPromote->size() - i - 1) - : negZOrderListAfterPromote->at(negZOrderListAfterPromote->size() + posZOrderListAfterPromote->size() - i - 1); - - if (nodeBeforePromote != nodeAfterPromote && nodeAfterPromote != this) - return; - } - - m_descendantsAreContiguousInStackingOrder = true; -} - -void RenderLayerStackingNode::collectBeforePromotionZOrderList(RenderLayerStackingNode* ancestorStackingNode, - OwnPtr<Vector<RenderLayerStackingNode*> >& posZOrderList, OwnPtr<Vector<RenderLayerStackingNode*> >& negZOrderList) -{ - ancestorStackingNode->rebuildZOrderLists(posZOrderList, negZOrderList, this, OnlyStackingContextsCanBeStackingContainers); - - const RenderLayer* currentLayer = layer(); - const RenderLayer* positionedAncestor = currentLayer->parent(); - while (positionedAncestor && !positionedAncestor->isPositionedContainer() && !positionedAncestor->stackingNode()->isStackingContext()) - positionedAncestor = positionedAncestor->parent(); - if (positionedAncestor && (!positionedAncestor->isPositionedContainer() || positionedAncestor->stackingNode()->isStackingContext())) - positionedAncestor = 0; - - if (!posZOrderList) - posZOrderList = adoptPtr(new Vector<RenderLayerStackingNode*>()); - else if (posZOrderList->find(this) != kNotFound) - return; - - // The current node will appear in the z-order lists after promotion, so - // for a meaningful comparison, we must insert it in the z-order lists - // before promotion if it does not appear there already. - if (!positionedAncestor) { - posZOrderList->prepend(this); - return; - } - - for (size_t index = 0; index < posZOrderList->size(); index++) { - if (posZOrderList->at(index)->layer() == positionedAncestor) { - posZOrderList->insert(index + 1, this); - return; - } - } -} - -void RenderLayerStackingNode::collectAfterPromotionZOrderList(RenderLayerStackingNode* ancestorStackingNode, - OwnPtr<Vector<RenderLayerStackingNode*> >& posZOrderList, OwnPtr<Vector<RenderLayerStackingNode*> >& negZOrderList) -{ - ancestorStackingNode->rebuildZOrderLists(posZOrderList, negZOrderList, this, ForceLayerToStackingContainer); + dirtyStackingContextZOrderLists(); } -// Compute what positive and negative z-order lists would look like before and -// after promotion, so we can later ensure that proper stacking order is -// preserved between the two sets of lists. -// -// A few examples: -// c = currentLayer -// - = negative z-order child of currentLayer -// + = positive z-order child of currentLayer -// a = positioned ancestor of currentLayer -// x = any other RenderLayer in the list -// -// (a) xxxxx-----++a+++x -// (b) xxx-----c++++++xx -// -// Normally the current layer would be painted in the normal flow list if it -// doesn't already appear in the positive z-order list. However, in the case -// that the layer has a positioned ancestor, it will paint directly after the -// positioned ancestor. In example (a), the current layer would be painted in -// the middle of its own positive z-order children, so promoting would cause a -// change in paint order (since a promoted layer will paint all of its positive -// z-order children strictly after it paints itself). -// -// In example (b), it is ok to promote the current layer only if it does not -// have a background. If it has a background, the background gets painted before -// the layer's negative z-order children, so again, a promotion would cause a -// change in paint order (causing the background to get painted after the -// negative z-order children instead of before). -// -void RenderLayerStackingNode::computePaintOrderList(PaintOrderListType type, Vector<RefPtr<Node> >& list) +RenderLayerStackingNode* RenderLayerStackingNode::ancestorStackingContextNode() const { - OwnPtr<Vector<RenderLayerStackingNode*> > posZOrderList; - OwnPtr<Vector<RenderLayerStackingNode*> > negZOrderList; - - RenderLayerStackingNode* stackingNode = ancestorStackingNode(); - if (!stackingNode) - return; - - switch (type) { - case BeforePromote: - collectBeforePromotionZOrderList(stackingNode, posZOrderList, negZOrderList); - break; - case AfterPromote: - collectAfterPromotionZOrderList(stackingNode, posZOrderList, negZOrderList); - break; - } - - if (negZOrderList) { - for (size_t index = 0; index < negZOrderList->size(); ++index) - list.append(negZOrderList->at(index)->renderer()->node()); - } - - if (posZOrderList) { - for (size_t index = 0; index < posZOrderList->size(); ++index) - list.append(posZOrderList->at(index)->renderer()->node()); + for (RenderLayer* ancestor = layer()->parent(); ancestor; ancestor = ancestor->parent()) { + RenderLayerStackingNode* stackingNode = ancestor->stackingNode(); + if (stackingNode->isStackingContext()) + return stackingNode; } -} - -bool RenderLayerStackingNode::descendantsAreContiguousInStackingOrder() const -{ - if (isStackingContext() || !ancestorStackingContainerNode()) - return true; - - ASSERT(!m_descendantsAreContiguousInStackingOrderDirty); - return m_descendantsAreContiguousInStackingOrder; -} - -bool RenderLayerStackingNode::setNeedsToBeStackingContainer(bool needsToBeStackingContainer) -{ - if (this->needsToBeStackingContainer() == needsToBeStackingContainer) - return false; - - // Count the total number of RenderLayers which need to be stacking - // containers some point. This should be recorded at most once per - // RenderLayer, so we check m_needsToBeStackingContainerHasBeenRecorded. - if (layer()->acceleratedCompositingForOverflowScrollEnabled() && !m_needsToBeStackingContainerHasBeenRecorded) { - blink::Platform::current()->histogramEnumeration("Renderer.CompositedScrolling", RenderLayer::NeedsToBeStackingContainerBucket, RenderLayer::CompositedScrollingHistogramMax); - m_needsToBeStackingContainerHasBeenRecorded = true; - } - - m_needsToBeStackingContainer = needsToBeStackingContainer; - - return true; -} - -RenderLayerStackingNode* RenderLayerStackingNode::ancestorStackingContainerNode() const -{ - RenderLayer* ancestor = layer()->parent(); - while (ancestor && !ancestor->stackingNode()->isStackingContainer()) - ancestor = ancestor->parent(); - if (ancestor) - return ancestor->stackingNode(); - return 0; -} - -RenderLayerStackingNode* RenderLayerStackingNode::ancestorStackingNode() const -{ - RenderLayer* ancestor = layer()->parent(); - while (ancestor && !ancestor->stackingNode()->isStackingContext()) - ancestor = ancestor->parent(); - if (ancestor) - return ancestor->stackingNode(); return 0; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerStackingNode.h b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerStackingNode.h index 12d7490fd8f..abe6b68c218 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerStackingNode.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerStackingNode.h @@ -65,20 +65,7 @@ public: int zIndex() const { return renderer()->style()->zIndex(); } // A stacking context is a layer that has a non-auto z-index. - bool isStackingContext() const { return isStackingContext(renderer()->style()); } - - // A stacking container can have z-order lists. All stacking contexts are - // stacking containers, but the converse is not true. Layers that use - // composited scrolling are stacking containers, but they may not - // necessarily be stacking contexts. - bool isStackingContainer() const { return isStackingContext() || needsToBeStackingContainer(); } - - bool setNeedsToBeStackingContainer(bool); - - // Returns true if z ordering would not change if this layer were a stacking container. - bool descendantsAreContiguousInStackingOrder() const; - void setDescendantsAreContiguousInStackingOrderDirty(bool flag) { m_descendantsAreContiguousInStackingOrderDirty = flag; } - void updateDescendantsAreContiguousInStackingOrder(); + bool isStackingContext() const { return !renderer()->style()->hasAutoZIndex(); } // Update our normal and z-index lists. void updateLayerListsIfNeeded(); @@ -87,31 +74,28 @@ public: void dirtyZOrderLists(); void updateZOrderLists(); void clearZOrderLists(); - void dirtyStackingContainerZOrderLists(); + void dirtyStackingContextZOrderLists(); bool hasPositiveZOrderList() const { return posZOrderList() && posZOrderList()->size(); } bool hasNegativeZOrderList() const { return negZOrderList() && negZOrderList()->size(); } + // FIXME: should check for dirtiness here? bool isNormalFlowOnly() const { return m_isNormalFlowOnly; } void updateIsNormalFlowOnly(); bool normalFlowListDirty() const { return m_normalFlowListDirty; } void dirtyNormalFlowList(); - enum PaintOrderListType {BeforePromote, AfterPromote}; - void computePaintOrderList(PaintOrderListType, Vector<RefPtr<Node> >&); - void updateStackingNodesAfterStyleChange(const RenderStyle* oldStyle); - RenderLayerStackingNode* ancestorStackingContainerNode() const; - RenderLayerStackingNode* ancestorStackingNode() const; + RenderLayerStackingNode* ancestorStackingContextNode() const; - // Gets the enclosing stacking container for this node, possibly the node - // itself, if it is a stacking container. - RenderLayerStackingNode* enclosingStackingContainerNode() { return isStackingContainer() ? this : ancestorStackingContainerNode(); } + // Gets the enclosing stacking context for this node, possibly the node + // itself, if it is a stacking context. + RenderLayerStackingNode* enclosingStackingContextNode() { return isStackingContext() ? this : ancestorStackingContextNode(); } RenderLayer* layer() const { return m_layer; } -#if !ASSERT_DISABLED +#if ASSERT_ENABLED bool layerListMutationAllowed() const { return m_layerListMutationAllowed; } void setLayerListMutationAllowed(bool flag) { m_layerListMutationAllowed = flag; } #endif @@ -124,7 +108,7 @@ private: Vector<RenderLayerStackingNode*>* posZOrderList() const { ASSERT(!m_zOrderListsDirty); - ASSERT(isStackingContainer() || !m_posZOrderList); + ASSERT(isStackingContext() || !m_posZOrderList); return m_posZOrderList.get(); } @@ -137,33 +121,14 @@ private: Vector<RenderLayerStackingNode*>* negZOrderList() const { ASSERT(!m_zOrderListsDirty); - ASSERT(isStackingContainer() || !m_negZOrderList); + ASSERT(isStackingContext() || !m_negZOrderList); return m_negZOrderList.get(); } - enum CollectLayersBehavior { - ForceLayerToStackingContainer, - OverflowScrollCanBeStackingContainers, - OnlyStackingContextsCanBeStackingContainers - }; - - bool isStackingContext(const RenderStyle*) const; - void rebuildZOrderLists(); + void collectLayers(OwnPtr<Vector<RenderLayerStackingNode*> >& posZOrderList, OwnPtr<Vector<RenderLayerStackingNode*> >& negZOrderList); - // layerToForceAsStackingContainer allows us to build pre-promotion and - // post-promotion layer lists, by allowing us to treat a layer as if it is a - // stacking context, without adding a new member to RenderLayer or modifying - // the style (which could cause extra allocations). - void rebuildZOrderLists(OwnPtr<Vector<RenderLayerStackingNode*> >&, OwnPtr<Vector<RenderLayerStackingNode*> >&, - const RenderLayerStackingNode* nodeToForceAsStackingContainer = 0, - CollectLayersBehavior = OverflowScrollCanBeStackingContainers); - - void collectLayers(OwnPtr<Vector<RenderLayerStackingNode*> >&, - OwnPtr<Vector<RenderLayerStackingNode*> >&, const RenderLayerStackingNode* nodeToForceAsStackingContainer = 0, - CollectLayersBehavior = OverflowScrollCanBeStackingContainers); - -#if !ASSERT_DISABLED +#if ASSERT_ENABLED bool isInStackingParentZOrderLists() const; bool isInStackingParentNormalFlowList() const; void updateStackingParentForZOrderLists(RenderLayerStackingNode* stackingParent); @@ -172,21 +137,10 @@ private: #endif bool shouldBeNormalFlowOnly() const; - bool shouldBeNormalFlowOnlyIgnoringCompositedScrolling() const; void updateNormalFlowList(); - void dirtyNormalFlowListCanBePromotedToStackingContainer(); - - void dirtySiblingStackingNodeCanBePromotedToStackingContainer(); - - void collectBeforePromotionZOrderList(RenderLayerStackingNode*, - OwnPtr<Vector<RenderLayerStackingNode*> >& posZOrderList, OwnPtr<Vector<RenderLayerStackingNode*> >& negZOrderList); - void collectAfterPromotionZOrderList(RenderLayerStackingNode*, - OwnPtr<Vector<RenderLayerStackingNode*> >& posZOrderList, OwnPtr<Vector<RenderLayerStackingNode*> >& negZOrderList); - bool isDirtyStackingContainer() const { return m_zOrderListsDirty && isStackingContainer(); } - - bool needsToBeStackingContainer() const; + bool isDirtyStackingContext() const { return m_zOrderListsDirty && isStackingContext(); } RenderLayerCompositor* compositor() const; // FIXME: Investigate changing this to Renderbox. @@ -194,31 +148,21 @@ private: RenderLayer* m_layer; - // For stacking contexts, m_posZOrderList holds a sorted list of all the - // descendant nodes within the stacking context that have z-indices of 0 or greater - // (auto will count as 0). m_negZOrderList holds descendants within our stacking context with negative - // z-indices. + // m_posZOrderList holds a sorted list of all the descendant nodes within + // that have z-indices of 0 or greater (auto will count as 0). + // m_negZOrderList holds descendants within our stacking context with + // negative z-indices. OwnPtr<Vector<RenderLayerStackingNode*> > m_posZOrderList; OwnPtr<Vector<RenderLayerStackingNode*> > m_negZOrderList; - // This list contains child nodes that cannot create stacking contexts. For now it is just - // overflow layers, but that may change in the future. + // This list contains child nodes that cannot create stacking contexts. OwnPtr<Vector<RenderLayerStackingNode*> > m_normalFlowList; - // If this is true, then no non-descendant appears between any of our - // descendants in stacking order. This is one of the requirements of being - // able to safely become a stacking context. - unsigned m_descendantsAreContiguousInStackingOrder : 1; - unsigned m_descendantsAreContiguousInStackingOrderDirty : 1; - unsigned m_zOrderListsDirty : 1; unsigned m_normalFlowListDirty: 1; unsigned m_isNormalFlowOnly : 1; - unsigned m_needsToBeStackingContainer : 1; - unsigned m_needsToBeStackingContainerHasBeenRecorded : 1; - -#if !ASSERT_DISABLED +#if ASSERT_ENABLED unsigned m_layerListMutationAllowed : 1; RenderLayerStackingNode* m_stackingParent; #endif @@ -226,9 +170,9 @@ private: inline void RenderLayerStackingNode::clearZOrderLists() { - ASSERT(!isStackingContainer()); + ASSERT(!isStackingContext()); -#if !ASSERT_DISABLED +#if ASSERT_ENABLED updateStackingParentForZOrderLists(0); #endif @@ -241,7 +185,7 @@ inline void RenderLayerStackingNode::updateZOrderLists() if (!m_zOrderListsDirty) return; - if (!isStackingContainer()) { + if (!isStackingContext()) { clearZOrderLists(); m_zOrderListsDirty = false; return; @@ -250,7 +194,7 @@ inline void RenderLayerStackingNode::updateZOrderLists() rebuildZOrderLists(); } -#if !ASSERT_DISABLED +#if ASSERT_ENABLED class LayerListMutationDetector { public: explicit LayerListMutationDetector(RenderLayerStackingNode* stackingNode) diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerStackingNodeIterator.h b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerStackingNodeIterator.h index 7682ea33d58..b230371fe1a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerStackingNodeIterator.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerStackingNodeIterator.h @@ -42,7 +42,6 @@ enum ChildrenIteration { AllChildren = NegativeZOrderChildren | NormalFlowChildren | PositiveZOrderChildren }; -class RenderLayer; class RenderLayerStackingNode; // This iterator walks the RenderLayerStackingNode lists in the following order: diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLineBoxList.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderLineBoxList.cpp index 085224721fe..9e0f01a30bc 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLineBoxList.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLineBoxList.cpp @@ -170,27 +170,25 @@ bool RenderLineBoxList::rangeIntersectsRect(RenderBoxModelObject* renderer, Layo return true; } -bool RenderLineBoxList::anyLineIntersectsRect(RenderBoxModelObject* renderer, const LayoutRect& rect, const LayoutPoint& offset, LayoutUnit outlineSize) const +bool RenderLineBoxList::anyLineIntersectsRect(RenderBoxModelObject* renderer, const LayoutRect& rect, const LayoutPoint& offset) const { // We can check the first box and last box and avoid painting/hit testing if we don't // intersect. This is a quick short-circuit that we can take to avoid walking any lines. // FIXME: This check is flawed in the following extremely obscure way: // if some line in the middle has a huge overflow, it might actually extend below the last line. - RootInlineBox* firstRootBox = firstLineBox()->root(); - RootInlineBox* lastRootBox = lastLineBox()->root(); - LayoutUnit firstLineTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox->lineTop()); - LayoutUnit lastLineBottom = lastLineBox()->logicalBottomVisualOverflow(lastRootBox->lineBottom()); - LayoutUnit logicalTop = firstLineTop - outlineSize; - LayoutUnit logicalBottom = outlineSize + lastLineBottom; - - return rangeIntersectsRect(renderer, logicalTop, logicalBottom, rect, offset); + RootInlineBox& firstRootBox = firstLineBox()->root(); + RootInlineBox& lastRootBox = lastLineBox()->root(); + LayoutUnit firstLineTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox.lineTop()); + LayoutUnit lastLineBottom = lastLineBox()->logicalBottomVisualOverflow(lastRootBox.lineBottom()); + + return rangeIntersectsRect(renderer, firstLineTop, lastLineBottom, rect, offset); } bool RenderLineBoxList::lineIntersectsDirtyRect(RenderBoxModelObject* renderer, InlineFlowBox* box, const PaintInfo& paintInfo, const LayoutPoint& offset) const { - RootInlineBox* root = box->root(); - LayoutUnit logicalTop = min<LayoutUnit>(box->logicalTopVisualOverflow(root->lineTop()), root->selectionTop()) - renderer->maximalOutlineSize(paintInfo.phase); - LayoutUnit logicalBottom = box->logicalBottomVisualOverflow(root->lineBottom()) + renderer->maximalOutlineSize(paintInfo.phase); + RootInlineBox& root = box->root(); + LayoutUnit logicalTop = min<LayoutUnit>(box->logicalTopVisualOverflow(root.lineTop()), root.selectionTop()); + LayoutUnit logicalBottom = box->logicalBottomVisualOverflow(root.lineBottom()); return rangeIntersectsRect(renderer, logicalTop, logicalBottom, paintInfo.rect, offset); } @@ -209,8 +207,7 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, PaintInfo& paintIn if (!firstLineBox()) return; - LayoutUnit outlineSize = renderer->maximalOutlineSize(paintInfo.phase); - if (!anyLineIntersectsRect(renderer, paintInfo.rect, paintOffset, outlineSize)) + if (!anyLineIntersectsRect(renderer, paintInfo.rect, paintOffset)) return; PaintInfo info(paintInfo); @@ -222,8 +219,8 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, PaintInfo& paintIn // based off positions of our first line box or our last line box. for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { if (lineIntersectsDirtyRect(renderer, curr, info, paintOffset)) { - RootInlineBox* root = curr->root(); - curr->paint(info, paintOffset, root->lineTop(), root->lineBottom()); + RootInlineBox& root = curr->root(); + curr->paint(info, paintOffset, root.lineTop(), root.lineBottom()); } } @@ -260,9 +257,9 @@ bool RenderLineBoxList::hitTest(RenderBoxModelObject* renderer, const HitTestReq // them further. Note that boxes can easily overlap, so we can't make any assumptions // based off positions of our first line box or our last line box. for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevLineBox()) { - RootInlineBox* root = curr->root(); - if (rangeIntersectsRect(renderer, curr->logicalTopVisualOverflow(root->lineTop()), curr->logicalBottomVisualOverflow(root->lineBottom()), rect, accumulatedOffset)) { - bool inside = curr->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, root->lineTop(), root->lineBottom()); + RootInlineBox& root = curr->root(); + if (rangeIntersectsRect(renderer, curr->logicalTopVisualOverflow(root.lineTop()), curr->logicalBottomVisualOverflow(root.lineBottom()), rect, accumulatedOffset)) { + bool inside = curr->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, root.lineTop(), root.lineBottom()); if (inside) { renderer->updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); return true; @@ -304,15 +301,15 @@ void RenderLineBoxList::dirtyLinesFromChangedChild(RenderObject* container, Rend if (curr->isReplaced()) { InlineBox* wrapper = toRenderBox(curr)->inlineBoxWrapper(); if (wrapper) - box = wrapper->root(); + box = &wrapper->root(); } else if (curr->isText()) { InlineTextBox* textBox = toRenderText(curr)->lastTextBox(); if (textBox) - box = textBox->root(); + box = &textBox->root(); } else if (curr->isRenderInline()) { InlineBox* lastSiblingBox = toRenderInline(curr)->lastLineBoxIncludingCulling(); if (lastSiblingBox) - box = lastSiblingBox->root(); + box = &lastSiblingBox->root(); } if (box) @@ -331,7 +328,7 @@ void RenderLineBoxList::dirtyLinesFromChangedChild(RenderObject* container, Rend } return; } - box = firstBox->root(); + box = &firstBox->root(); } // If we found a line box, then dirty it. diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLineBoxList.h b/chromium/third_party/WebKit/Source/core/rendering/RenderLineBoxList.h index b57a4a03806..611b4d42ba8 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLineBoxList.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLineBoxList.h @@ -67,7 +67,7 @@ public: bool hitTest(RenderBoxModelObject*, const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) const; private: - bool anyLineIntersectsRect(RenderBoxModelObject*, const LayoutRect&, const LayoutPoint&, LayoutUnit outlineSize = 0) const; + bool anyLineIntersectsRect(RenderBoxModelObject*, const LayoutRect&, const LayoutPoint&) const; bool lineIntersectsDirtyRect(RenderBoxModelObject*, InlineFlowBox*, const PaintInfo&, const LayoutPoint&) const; bool rangeIntersectsRect(RenderBoxModelObject*, LayoutUnit logicalTop, LayoutUnit logicalBottom, const LayoutRect&, const LayoutPoint&) const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderListBox.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderListBox.cpp index bc4617f29ff..82c22b91945 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderListBox.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderListBox.cpp @@ -30,25 +30,23 @@ #include "config.h" #include "core/rendering/RenderListBox.h" -#include <math.h> -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/accessibility/AXObjectCache.h" #include "core/css/CSSFontSelector.h" #include "core/css/resolver/StyleResolver.h" #include "core/dom/Document.h" #include "core/dom/NodeRenderStyle.h" #include "core/editing/FrameSelection.h" +#include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/html/HTMLOptGroupElement.h" #include "core/html/HTMLOptionElement.h" #include "core/html/HTMLSelectElement.h" #include "core/page/EventHandler.h" #include "core/page/FocusController.h" -#include "core/frame/Frame.h" -#include "core/frame/FrameView.h" #include "core/page/Page.h" #include "core/page/SpatialNavigation.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/PaintInfo.h" #include "core/rendering/RenderScrollbar.h" #include "core/rendering/RenderText.h" @@ -57,6 +55,8 @@ #include "platform/fonts/FontCache.h" #include "platform/graphics/GraphicsContext.h" #include "platform/scroll/Scrollbar.h" +#include "platform/text/BidiTextRun.h" +#include <math.h> using namespace std; @@ -86,10 +86,11 @@ RenderListBox::RenderListBox(Element* element) , m_inAutoscroll(false) , m_optionsWidth(0) , m_indexOffset(0) + , m_listItemCount(0) { ASSERT(element); ASSERT(element->isHTMLElement()); - ASSERT(element->hasTagName(HTMLNames::selectTag)); + ASSERT(isHTMLSelectElement(element)); if (FrameView* frameView = frame()->view()) frameView->addScrollableArea(this); @@ -103,6 +104,13 @@ RenderListBox::~RenderListBox() frameView->removeScrollableArea(this); } +// FIXME: Instead of this hack we should add a ShadowRoot to <select> with no insertion point +// to prevent children from rendering. +bool RenderListBox::isChildAllowed(RenderObject* object, RenderStyle*) const +{ + return object->isAnonymous() && !object->isRenderFullScreen(); +} + inline HTMLSelectElement* RenderListBox::selectElement() const { return toHTMLSelectElement(node()); @@ -111,30 +119,46 @@ inline HTMLSelectElement* RenderListBox::selectElement() const void RenderListBox::updateFromElement() { FontCachePurgePreventer fontCachePurgePreventer; - if (m_optionsChanged) { - const Vector<HTMLElement*>& listItems = selectElement()->listItems(); - int size = numItems(); + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); + int size = static_cast<int>(listItems.size()); float width = 0; + m_listItemCount = 0; for (int i = 0; i < size; ++i) { - HTMLElement* element = listItems[i]; + const HTMLElement& element = *listItems[i]; + String text; Font itemFont = style()->font(); - if (element->hasTagName(optionTag)) { - text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel(); + if (isHTMLOptionElement(element)) { + const HTMLOptionElement& optionElement = toHTMLOptionElement(element); + if (optionElement.isDisplayNone()) + continue; + text = optionElement.textIndentedToRespectGroupLabel(); + ++m_listItemCount; } else if (isHTMLOptGroupElement(element)) { - text = toHTMLOptGroupElement(element)->groupLabelText(); + if (toHTMLOptGroupElement(element).isDisplayNone()) + continue; + text = toHTMLOptGroupElement(element).groupLabelText(); FontDescription d = itemFont.fontDescription(); d.setWeight(d.bolderWeight()); - itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); + itemFont = Font(d); itemFont.update(document().styleEngine()->fontSelector()); + ++m_listItemCount; + } else if (isHTMLHRElement(element)) { + // HTMLSelect adds it to its list, so we will also add it to match the count. + ++m_listItemCount; + continue; } if (!text.isEmpty()) { applyTextTransform(style(), text, ' '); - // FIXME: Why is this always LTR? Can't text direction affect the width? + + bool hasStrongDirectionality; + TextDirection direction = determineDirectionality(text, hasStrongDirectionality); TextRun textRun = constructTextRun(this, itemFont, text, style(), TextRun::AllowTrailingExpansion); + if (hasStrongDirectionality) + textRun.setDirection(direction); textRun.disableRoundingHacks(); float textWidth = itemFont.width(textRun); width = max(width, textWidth); @@ -145,13 +169,13 @@ void RenderListBox::updateFromElement() setHasVerticalScrollbar(true); - setNeedsLayoutAndPrefWidthsRecalc(); + setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } } void RenderListBox::selectionChanged() { - repaint(); + paintInvalidationForWholeRenderer(); if (!m_inAutoscroll) { if (m_optionsChanged || needsLayout()) m_scrollToRevealSelectionAfterLayout = true; @@ -165,7 +189,6 @@ void RenderListBox::selectionChanged() void RenderListBox::layout() { - LayoutRectRecorder recorder(*this); RenderBlockFlow::layout(); if (m_vBar) { @@ -179,27 +202,32 @@ void RenderListBox::layout() } if (m_scrollToRevealSelectionAfterLayout) { - LayoutStateDisabler layoutStateDisabler(view()); + ForceHorriblySlowRectMapping slowRectMapping(*this); scrollToRevealSelection(); } } +void RenderListBox::invalidateTreeAfterLayout(const RenderLayerModelObject& invalidationContainer) +{ + repaintScrollbarIfNeeded(); + RenderBox::invalidateTreeAfterLayout(invalidationContainer); +} + void RenderListBox::scrollToRevealSelection() { HTMLSelectElement* select = selectElement(); m_scrollToRevealSelectionAfterLayout = false; - int firstIndex = select->activeSelectionStartListIndex(); - if (firstIndex >= 0 && !listIndexIsVisible(select->activeSelectionEndListIndex())) - scrollToRevealElementAtListIndex(firstIndex); + int firstIndex = listIndexToRenderListBoxIndex(select->activeSelectionStartListIndex()); + int lastIndex = listIndexToRenderListBoxIndex(select->activeSelectionEndListIndex()); + if (firstIndex >= 0 && !listIndexIsVisible(lastIndex)) + scrollToRevealElementAtListIndexInternal(firstIndex); } void RenderListBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const { - maxLogicalWidth = m_optionsWidth + 2 * optionsSpacingHorizontal; - if (m_vBar) - maxLogicalWidth += verticalScrollbarWidth(); + maxLogicalWidth = m_optionsWidth + 2 * optionsSpacingHorizontal + verticalScrollbarWidth(); if (!style()->width().isPercent()) minLogicalWidth = maxLogicalWidth; } @@ -210,20 +238,21 @@ void RenderListBox::computePreferredLogicalWidths() m_minPreferredLogicalWidth = 0; m_maxPreferredLogicalWidth = 0; + RenderStyle* styleToUse = style(); - if (style()->width().isFixed() && style()->width().value() > 0) - m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->width().value()); + if (styleToUse->width().isFixed() && styleToUse->width().value() > 0) + m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->width().value()); else computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth); - if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) { - m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value())); - m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value())); + if (styleToUse->minWidth().isFixed() && styleToUse->minWidth().value() > 0) { + m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->minWidth().value())); + m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->minWidth().value())); } - if (style()->maxWidth().isFixed()) { - m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value())); - m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value())); + if (styleToUse->maxWidth().isFixed()) { + m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->maxWidth().value())); + m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->maxWidth().value())); } LayoutUnit toAdd = borderAndPaddingWidth(); @@ -250,7 +279,7 @@ int RenderListBox::numVisibleItems() const int RenderListBox::numItems() const { - return selectElement()->listItems().size(); + return m_listItemCount; } LayoutUnit RenderListBox::listHeight() const @@ -260,7 +289,12 @@ LayoutUnit RenderListBox::listHeight() const void RenderListBox::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const { - LayoutUnit height = itemHeight() * size() - rowSpacing + borderAndPaddingHeight(); + LayoutUnit height = itemHeight() * size() - rowSpacing; + // FIXME: The item height should have been added before updateLogicalHeight was called to avoid this hack. + updateIntrinsicContentLogicalHeight(height); + + height += borderAndPaddingHeight(); + RenderBox::computeLogicalHeight(height, logicalTop, computedValues); } @@ -269,7 +303,7 @@ int RenderListBox::baselinePosition(FontBaseline baselineType, bool firstLine, L return RenderBox::baselinePosition(baselineType, firstLine, lineDirection, linePositionMode) - baselineAdjustment; } -LayoutRect RenderListBox::itemBoundingBoxRect(const LayoutPoint& additionalOffset, int index) +LayoutRect RenderListBox::itemBoundingBoxRectInternal(const LayoutPoint& additionalOffset, int index) const { // For RTL, items start after the left-side vertical scrollbar. int scrollbarOffset = style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? verticalScrollbarWidth() : 0; @@ -294,7 +328,7 @@ void RenderListBox::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOf } // Paint the children. - RenderBlock::paintObject(paintInfo, paintOffset); + RenderBlockFlow::paintObject(paintInfo, paintOffset); switch (paintInfo.phase) { // Depending on whether we have overlay scrollbars they @@ -324,24 +358,24 @@ void RenderListBox::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOf void RenderListBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer) { if (!isSpatialNavigationEnabled(frame())) - return RenderBlock::addFocusRingRects(rects, additionalOffset, paintContainer); + return RenderBlockFlow::addFocusRingRects(rects, additionalOffset, paintContainer); HTMLSelectElement* select = selectElement(); // Focus the last selected item. int selectedItem = select->activeSelectionEndListIndex(); if (selectedItem >= 0) { - rects.append(pixelSnappedIntRect(itemBoundingBoxRect(additionalOffset, selectedItem))); + rects.append(pixelSnappedIntRect(itemBoundingBoxRectInternal(additionalOffset, selectedItem))); return; } // No selected items, find the first non-disabled item. int size = numItems(); - const Vector<HTMLElement*>& listItems = select->listItems(); + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = select->listItems(); for (int i = 0; i < size; ++i) { - HTMLElement* element = listItems[i]; - if (element->hasTagName(optionTag) && !element->isDisabledFormControl()) { - rects.append(pixelSnappedIntRect(itemBoundingBoxRect(additionalOffset, i))); + HTMLElement* element = listItems[renderListBoxIndexToListIndex(i)]; + if (isHTMLOptionElement(*element) && !element->isDisabledFormControl()) { + rects.append(pixelSnappedIntRect(itemBoundingBoxRectInternal(additionalOffset, i))); return; } } @@ -353,7 +387,7 @@ int RenderListBox::scrollbarLeft() const if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) scrollbarLeft = borderLeft(); else - scrollbarLeft = width() - borderRight() - verticalScrollbarWidth(); + scrollbarLeft = width() - borderRight() - (m_vBar ? m_vBar->width() : 0); return scrollbarLeft; } @@ -362,7 +396,7 @@ void RenderListBox::paintScrollbar(PaintInfo& paintInfo, const LayoutPoint& pain if (m_vBar) { IntRect scrollRect = pixelSnappedIntRect(paintOffset.x() + scrollbarLeft(), paintOffset.y() + borderTop(), - verticalScrollbarWidth(), + m_vBar->width(), height() - (borderTop() + borderBottom())); m_vBar->setFrameRect(scrollRect); m_vBar->paint(paintInfo.context, paintInfo.rect); @@ -395,8 +429,8 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, const LayoutPoint& HTMLSelectElement* select = selectElement(); - const Vector<HTMLElement*>& listItems = select->listItems(); - HTMLElement* element = listItems[listIndex]; + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = select->listItems(); + HTMLElement* element = listItems[renderListBoxIndexToListIndex(listIndex)]; RenderStyle* itemStyle = element->renderStyle(); if (!itemStyle) @@ -406,15 +440,15 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, const LayoutPoint& return; String itemText; - bool isOptionElement = element->hasTagName(optionTag); + bool isOptionElement = isHTMLOptionElement(*element); if (isOptionElement) - itemText = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel(); - else if (isHTMLOptGroupElement(element)) - itemText = toHTMLOptGroupElement(element)->groupLabelText(); + itemText = toHTMLOptionElement(*element).textIndentedToRespectGroupLabel(); + else if (isHTMLOptGroupElement(*element)) + itemText = toHTMLOptGroupElement(*element).groupLabelText(); applyTextTransform(style(), itemText, ' '); Color textColor = element->renderStyle() ? resolveColor(element->renderStyle(), CSSPropertyColor) : resolveColor(CSSPropertyColor); - if (isOptionElement && toHTMLOptionElement(element)->selected()) { + if (isOptionElement && ((toHTMLOptionElement(*element).selected() && select->suggestedIndex() < 0) || listIndex == select->suggestedIndex())) { if (frame()->selection().isFocusedAndActive() && document().focusedElement() == node()) textColor = RenderTheme::theme().activeListBoxSelectionForegroundColor(); // Honor the foreground color for disabled items @@ -426,13 +460,13 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, const LayoutPoint& TextRun textRun(itemText, 0, 0, TextRun::AllowTrailingExpansion, itemStyle->direction(), isOverride(itemStyle->unicodeBidi()), true, TextRun::NoRounding); Font itemFont = style()->font(); - LayoutRect r = itemBoundingBoxRect(paintOffset, listIndex); + LayoutRect r = itemBoundingBoxRectInternal(paintOffset, listIndex); r.move(itemOffsetForAlignment(textRun, itemStyle, itemFont, r)); - if (isHTMLOptGroupElement(element)) { + if (isHTMLOptGroupElement(*element)) { FontDescription d = itemFont.fontDescription(); d.setWeight(d.bolderWeight()); - itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); + itemFont = Font(d); itemFont.update(document().styleEngine()->fontSelector()); } @@ -444,11 +478,11 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, const LayoutPoint& void RenderListBox::paintItemBackground(PaintInfo& paintInfo, const LayoutPoint& paintOffset, int listIndex) { - const Vector<HTMLElement*>& listItems = selectElement()->listItems(); - HTMLElement* element = listItems[listIndex]; + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); + HTMLElement* element = listItems[renderListBoxIndexToListIndex(listIndex)]; Color backColor; - if (element->hasTagName(optionTag) && toHTMLOptionElement(element)->selected()) { + if (isHTMLOptionElement(*element) && ((toHTMLOptionElement(*element).selected() && selectElement()->suggestedIndex() < 0) || listIndex == selectElement()->suggestedIndex())) { if (frame()->selection().isFocusedAndActive() && document().focusedElement() == node()) backColor = RenderTheme::theme().activeListBoxSelectionBackgroundColor(); else @@ -459,7 +493,7 @@ void RenderListBox::paintItemBackground(PaintInfo& paintInfo, const LayoutPoint& // Draw the background for this list box item if (!element->renderStyle() || element->renderStyle()->visibility() != HIDDEN) { - LayoutRect itemRect = itemBoundingBoxRect(paintOffset, listIndex); + LayoutRect itemRect = itemBoundingBoxRectInternal(paintOffset, listIndex); itemRect.intersect(controlClipRect(paintOffset)); paintInfo.context->fillRect(pixelSnappedIntRect(itemRect), backColor); } @@ -482,7 +516,7 @@ bool RenderListBox::isPointInOverflowControl(HitTestResult& result, const Layout return false; } -int RenderListBox::listIndexAtOffset(const LayoutSize& offset) +int RenderListBox::listIndexAtOffset(const LayoutSize& offset) const { if (!numItems()) return -1; @@ -498,7 +532,7 @@ int RenderListBox::listIndexAtOffset(const LayoutSize& offset) return -1; int newOffset = (offset.height() - borderTop() - paddingTop()) / itemHeight() + m_indexOffset; - return newOffset < numItems() ? newOffset : -1; + return newOffset < numItems() ? renderListBoxIndexToListIndex(newOffset) : -1; } void RenderListBox::panScroll(const IntPoint& panStartMousePosition) @@ -527,8 +561,7 @@ void RenderListBox::panScroll(const IntPoint& panStartMousePosition) return; if (yDelta > 0) - //offsetY = view()->viewHeight(); - absOffset.move(0, listHeight()); + absOffset.move(0, listHeight().toFloat()); else if (yDelta < 0) yDelta--; @@ -556,10 +589,10 @@ int RenderListBox::scrollToward(const IntPoint& destination) int rows = numVisibleItems(); int offset = m_indexOffset; - if (positionOffset.height() < borderTop() + paddingTop() && scrollToRevealElementAtListIndex(offset - 1)) + if (positionOffset.height() < borderTop() + paddingTop() && scrollToRevealElementAtListIndexInternal(offset - 1)) return offset - 1; - if (positionOffset.height() > height() - paddingBottom() - borderBottom() && scrollToRevealElementAtListIndex(offset + rows)) + if (positionOffset.height() > height() - paddingBottom() - borderBottom() && scrollToRevealElementAtListIndexInternal(offset + rows)) return offset + rows - 1; return listIndexAtOffset(positionOffset); @@ -578,9 +611,9 @@ void RenderListBox::autoscroll(const IntPoint&) m_inAutoscroll = true; if (!select->multiple()) - select->setActiveSelectionAnchorIndex(endIndex); + select->setActiveSelectionAnchorIndex(renderListBoxIndexToListIndex(endIndex)); - select->setActiveSelectionEndIndex(endIndex); + select->setActiveSelectionEndIndex(renderListBoxIndexToListIndex(endIndex)); select->updateListBoxSelection(!select->multiple()); m_inAutoscroll = false; } @@ -594,7 +627,7 @@ void RenderListBox::stopAutoscroll() selectElement()->listBoxOnChange(); } -bool RenderListBox::scrollToRevealElementAtListIndex(int index) +bool RenderListBox::scrollToRevealElementAtListIndexInternal(int index) { if (index < 0 || index >= numItems() || listIndexIsVisible(index)) return false; @@ -610,7 +643,7 @@ bool RenderListBox::scrollToRevealElementAtListIndex(int index) return true; } -bool RenderListBox::listIndexIsVisible(int index) +bool RenderListBox::listIndexIsVisible(int index) const { return index >= m_indexOffset && index < m_indexOffset + numVisibleItems(); } @@ -620,13 +653,6 @@ bool RenderListBox::scroll(ScrollDirection direction, ScrollGranularity granular return ScrollableArea::scroll(direction, granularity, multiplier); } -void RenderListBox::valueChanged(unsigned listIndex) -{ - HTMLSelectElement* element = selectElement(); - element->setSelectedIndex(element->listToOptionIndex(listIndex)); - element->dispatchFormControlChangeEvent(); -} - int RenderListBox::scrollSize(ScrollbarOrientation orientation) const { return orientation == VerticalScrollbar ? (numItems() - numVisibleItems()) : 0; @@ -648,7 +674,12 @@ void RenderListBox::scrollTo(int newOffset) return; m_indexOffset = newOffset; - repaint(); + + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && frameView()->isInPerformLayout()) + setShouldDoFullPaintInvalidationAfterLayout(true); + else + paintInvalidationForWholeRenderer(); + node()->document().enqueueScrollEventForNode(node()); } @@ -664,32 +695,32 @@ int RenderListBox::verticalScrollbarWidth() const // FIXME: We ignore padding in the vertical direction as far as these values are concerned, since that's // how the control currently paints. -int RenderListBox::scrollWidth() const +LayoutUnit RenderListBox::scrollWidth() const { // There is no horizontal scrolling allowed. - return pixelSnappedClientWidth(); + return clientWidth(); } -int RenderListBox::scrollHeight() const +LayoutUnit RenderListBox::scrollHeight() const { - return max(pixelSnappedClientHeight(), roundToInt(listHeight())); + return max(clientHeight(), listHeight()); } -int RenderListBox::scrollLeft() const +LayoutUnit RenderListBox::scrollLeft() const { return 0; } -void RenderListBox::setScrollLeft(int) +void RenderListBox::setScrollLeft(LayoutUnit) { } -int RenderListBox::scrollTop() const +LayoutUnit RenderListBox::scrollTop() const { return m_indexOffset * itemHeight(); } -void RenderListBox::setScrollTop(int newTop) +void RenderListBox::setScrollTop(LayoutUnit newTop) { // Determine an index and scroll to it. int index = newTop / itemHeight(); @@ -701,15 +732,15 @@ void RenderListBox::setScrollTop(int newTop) bool RenderListBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { - if (!RenderBlock::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction)) + if (!RenderBlockFlow::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction)) return false; - const Vector<HTMLElement*>& listItems = selectElement()->listItems(); + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); int size = numItems(); LayoutPoint adjustedLocation = accumulatedOffset + location(); for (int i = 0; i < size; ++i) { - if (itemBoundingBoxRect(adjustedLocation, i).contains(locationInContainer.point())) { - if (Element* node = listItems[i]) { + if (itemBoundingBoxRectInternal(adjustedLocation, i).contains(locationInContainer.point())) { + if (Element* node = listItems[renderListBoxIndexToListIndex(i)]) { result.setInnerNode(node); if (!result.innerNonSharedNode()) result.setInnerNonSharedNode(node); @@ -745,7 +776,22 @@ void RenderListBox::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& scrollRect.move(borderLeft(), borderTop()); else scrollRect.move(width() - borderRight() - scrollbar->width(), borderTop()); - repaintRectangle(scrollRect); + + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && frameView()->isInPerformLayout()) { + m_verticalBarDamage = scrollRect; + m_hasVerticalBarDamage = true; + } else { + invalidatePaintRectangle(scrollRect); + } +} + +void RenderListBox::repaintScrollbarIfNeeded() +{ + if (!hasVerticalBarDamage()) + return; + invalidatePaintRectangle(verticalBarDamage()); + + resetScrollbarDamage(); } IntRect RenderListBox::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const @@ -759,7 +805,7 @@ IntRect RenderListBox::convertFromScrollbarToContainingView(const Scrollbar* scr int scrollbarTop = borderTop(); rect.move(scrollbarLeft(), scrollbarTop); - return view->frameView()->convertFromRenderer(this, rect); + return view->frameView()->convertFromRenderer(*this, rect); } IntRect RenderListBox::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const @@ -768,7 +814,7 @@ IntRect RenderListBox::convertFromContainingViewToScrollbar(const Scrollbar* scr if (!view) return parentRect; - IntRect rect = view->frameView()->convertToRenderer(this, parentRect); + IntRect rect = view->frameView()->convertToRenderer(*this, parentRect); int scrollbarTop = borderTop(); rect.move(-scrollbarLeft(), -scrollbarTop); @@ -786,7 +832,7 @@ IntPoint RenderListBox::convertFromScrollbarToContainingView(const Scrollbar* sc int scrollbarTop = borderTop(); point.move(scrollbarLeft(), scrollbarTop); - return view->frameView()->convertFromRenderer(this, point); + return view->frameView()->convertFromRenderer(*this, point); } IntPoint RenderListBox::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const @@ -795,7 +841,7 @@ IntPoint RenderListBox::convertFromContainingViewToScrollbar(const Scrollbar* sc if (!view) return parentPoint; - IntPoint point = view->frameView()->convertToRenderer(this, parentPoint); + IntPoint point = view->frameView()->convertToRenderer(*this, parentPoint); int scrollbarTop = borderTop(); point.move(-scrollbarLeft(), -scrollbarTop); @@ -848,7 +894,7 @@ IntPoint RenderListBox::minimumScrollPosition() const IntPoint RenderListBox::maximumScrollPosition() const { - return IntPoint(0, numItems() - numVisibleItems()); + return IntPoint(0, std::max(numItems() - numVisibleItems(), 0)); } bool RenderListBox::userInputScrollable(ScrollbarOrientation orientation) const @@ -876,12 +922,6 @@ float RenderListBox::pixelStep(ScrollbarOrientation) const return 1.0f / itemHeight(); } -ScrollableArea* RenderListBox::enclosingScrollableArea() const -{ - // FIXME: Return a RenderLayer that's scrollable. - return 0; -} - IntRect RenderListBox::scrollableAreaBoundingBox() const { return absoluteBoundingBoxRect(); @@ -910,7 +950,7 @@ void RenderListBox::destroyScrollbar() ScrollableArea::willRemoveScrollbar(m_vBar.get(), VerticalScrollbar); m_vBar->removeFromParent(); m_vBar->disconnectFromScrollableArea(); - m_vBar = 0; + m_vBar = nullptr; } void RenderListBox::setHasVerticalScrollbar(bool hasScrollbar) @@ -931,4 +971,59 @@ void RenderListBox::setHasVerticalScrollbar(bool hasScrollbar) document().setAnnotatedRegionsDirty(true); } +int RenderListBox::renderListBoxIndexToListIndex(int index) const +{ + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); + const int size = static_cast<int>(listItems.size()); + + if (size == numItems()) + return index; + + int listBoxIndex = 0; + int listIndex = 0; + for (; listIndex < size; ++listIndex) { + const HTMLElement& element = *listItems[listIndex]; + if (isHTMLOptionElement(element) && toHTMLOptionElement(element).isDisplayNone()) + continue; + if (isHTMLOptGroupElement(element) && toHTMLOptGroupElement(element).isDisplayNone()) + continue; + if (index == listBoxIndex) + break; + ++listBoxIndex; + } + return listIndex; +} + +int RenderListBox::listIndexToRenderListBoxIndex(int index) const +{ + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); + const int size = static_cast<int>(listItems.size()); + + if (size == numItems()) + return index; + + int listBoxIndex = 0; + for (int listIndex = 0; listIndex < size; ++listIndex) { + const HTMLElement& element = *listItems[listIndex]; + if (isHTMLOptionElement(element) && toHTMLOptionElement(element).isDisplayNone()) + continue; + if (isHTMLOptGroupElement(element) && toHTMLOptGroupElement(element).isDisplayNone()) + continue; + if (index == listIndex) + break; + ++listBoxIndex; + } + return listBoxIndex; +} + +LayoutRect RenderListBox::itemBoundingBoxRect(const LayoutPoint& point, int index) const +{ + return itemBoundingBoxRectInternal(point, listIndexToRenderListBoxIndex(index)); +} + +bool RenderListBox::scrollToRevealElementAtListIndex(int index) +{ + return scrollToRevealElementAtListIndexInternal(listIndexToRenderListBoxIndex(index)); +} + } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderListBox.h b/chromium/third_party/WebKit/Source/core/rendering/RenderListBox.h index c86b50869bc..9a99eab5f17 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderListBox.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderListBox.h @@ -47,57 +47,58 @@ public: void setOptionsChanged(bool changed) { m_optionsChanged = changed; } - int listIndexAtOffset(const LayoutSize&); - LayoutRect itemBoundingBoxRect(const LayoutPoint&, int index); + int listIndexAtOffset(const LayoutSize&) const; + LayoutRect itemBoundingBoxRect(const LayoutPoint&, int index) const; bool scrollToRevealElementAtListIndex(int index); - bool listIndexIsVisible(int index); int scrollToward(const IntPoint&); // Returns the new index or -1 if no scroll occurred int size() const; + void repaintScrollbarIfNeeded(); + private: HTMLSelectElement* selectElement() const; - virtual const char* renderName() const { return "RenderListBox"; } + virtual const char* renderName() const OVERRIDE { return "RenderListBox"; } - virtual bool isListBox() const { return true; } + virtual bool isListBox() const OVERRIDE { return true; } + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; - virtual void updateFromElement(); - virtual bool hasControlClip() const { return true; } - virtual void paintObject(PaintInfo&, const LayoutPoint&); - virtual LayoutRect controlClipRect(const LayoutPoint&) const; + virtual void updateFromElement() OVERRIDE; + virtual bool hasControlClip() const OVERRIDE { return true; } + virtual void paintObject(PaintInfo&, const LayoutPoint&) OVERRIDE; + virtual LayoutRect controlClipRect(const LayoutPoint&) const OVERRIDE; - virtual bool isPointInOverflowControl(HitTestResult&, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset); + virtual bool isPointInOverflowControl(HitTestResult&, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset) OVERRIDE; virtual bool scroll(ScrollDirection, ScrollGranularity, float) OVERRIDE; virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE; virtual void computePreferredLogicalWidths() OVERRIDE; - virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const; + virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const OVERRIDE; virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE; - virtual void layout(); + virtual void layout() OVERRIDE; - virtual bool supportsPartialLayout() const OVERRIDE { return false; } + virtual void invalidateTreeAfterLayout(const RenderLayerModelObject&) OVERRIDE FINAL; virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) OVERRIDE; - virtual bool canBeProgramaticallyScrolled() const { return true; } - virtual void autoscroll(const IntPoint&); - virtual void stopAutoscroll(); + virtual bool canBeProgramaticallyScrolled() const OVERRIDE { return true; } + virtual void autoscroll(const IntPoint&) OVERRIDE; + virtual void stopAutoscroll() OVERRIDE; - virtual bool shouldPanScroll() const { return true; } - virtual void panScroll(const IntPoint&); + virtual void panScroll(const IntPoint&) OVERRIDE; - virtual int verticalScrollbarWidth() const; - virtual int scrollLeft() const; - virtual int scrollTop() const; - virtual int scrollWidth() const; - virtual int scrollHeight() const; - virtual void setScrollLeft(int); - virtual void setScrollTop(int); + virtual int verticalScrollbarWidth() const OVERRIDE; + virtual LayoutUnit scrollLeft() const OVERRIDE; + virtual LayoutUnit scrollTop() const OVERRIDE; + virtual LayoutUnit scrollWidth() const OVERRIDE; + virtual LayoutUnit scrollHeight() const OVERRIDE; + virtual void setScrollLeft(LayoutUnit) OVERRIDE; + virtual void setScrollTop(LayoutUnit) OVERRIDE; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; @@ -125,14 +126,14 @@ private: virtual IntPoint maximumScrollPosition() const OVERRIDE; virtual bool userInputScrollable(ScrollbarOrientation) const OVERRIDE; virtual bool shouldPlaceVerticalScrollbarOnLeft() const OVERRIDE; - virtual int lineStep(ScrollbarOrientation) const; - virtual int pageStep(ScrollbarOrientation) const; - virtual float pixelStep(ScrollbarOrientation) const; - - - virtual ScrollableArea* enclosingScrollableArea() const OVERRIDE; + virtual int lineStep(ScrollbarOrientation) const OVERRIDE; + virtual int pageStep(ScrollbarOrientation) const OVERRIDE; + virtual float pixelStep(ScrollbarOrientation) const OVERRIDE; virtual IntRect scrollableAreaBoundingBox() const OVERRIDE; + LayoutRect itemBoundingBoxRectInternal(const LayoutPoint&, int index) const; + bool scrollToRevealElementAtListIndexInternal(int index); + // NOTE: This should only be called by the overriden setScrollOffset from ScrollableArea. void scrollTo(int newOffset); @@ -141,8 +142,8 @@ private: void destroyScrollbar(); LayoutUnit itemHeight() const; - void valueChanged(unsigned listIndex); int numVisibleItems() const; + bool listIndexIsVisible(int index) const; int numItems() const; LayoutUnit listHeight() const; int scrollbarLeft() const; @@ -151,11 +152,15 @@ private: void paintItemBackground(PaintInfo&, const LayoutPoint&, int listIndex); void scrollToRevealSelection(); + int renderListBoxIndexToListIndex(int index) const; + int listIndexToRenderListBoxIndex(int index) const; + bool m_optionsChanged; bool m_scrollToRevealSelectionAfterLayout; bool m_inAutoscroll; int m_optionsWidth; int m_indexOffset; + int m_listItemCount; RefPtr<Scrollbar> m_vBar; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderListItem.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderListItem.cpp index b3b57a571ba..54d3d2d7e4b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderListItem.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderListItem.cpp @@ -24,10 +24,10 @@ #include "config.h" #include "core/rendering/RenderListItem.h" -#include "HTMLNames.h" -#include "core/dom/ElementTraversal.h" +#include "core/HTMLNames.h" +#include "core/dom/NodeRenderingTraversal.h" #include "core/html/HTMLOListElement.h" -#include "core/rendering/LayoutRectRecorder.h" +#include "core/rendering/FastTextAutosizer.h" #include "core/rendering/RenderListMarker.h" #include "core/rendering/RenderView.h" #include "wtf/StdLibExtras.h" @@ -51,15 +51,11 @@ RenderListItem::RenderListItem(Element* element) void RenderListItem::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - RenderBlock::styleDidChange(diff, oldStyle); + RenderBlockFlow::styleDidChange(diff, oldStyle); if (style()->listStyleType() != NoneListStyle || (style()->listStyleImage() && !style()->listStyleImage()->errorOccurred())) { RefPtr<RenderStyle> newStyle = RenderStyle::create(); - // Markers update their own margin style. By copying the existing style we can - // avoid an unnecessary layout in setStyle below. - if (m_marker) - newStyle->copyNonInheritedFrom(m_marker->style()); // The marker always inherits from the list item, regardless of where it might end // up (e.g., in some deeply nested line box). See CSS3 spec. newStyle->inheritFrom(style()); @@ -95,9 +91,9 @@ void RenderListItem::willBeRemovedFromTree() updateListMarkerNumbers(); } -static bool isList(const Node* node) +static bool isList(const Node& node) { - return (node->hasTagName(ulTag) || node->hasTagName(olTag)); + return isHTMLUListElement(node) || isHTMLOListElement(node); } // Returns the enclosing list with respect to the DOM order. @@ -106,8 +102,8 @@ static Node* enclosingList(const RenderListItem* listItem) Node* listItemNode = listItem->node(); Node* firstNode = 0; // We use parentNode because the enclosing list could be a ShadowRoot that's not Element. - for (Node* parent = listItemNode->parentNode(); parent; parent = parent->parentNode()) { - if (isList(parent)) + for (Node* parent = NodeRenderingTraversal::parent(listItemNode); parent; parent = NodeRenderingTraversal::parent(parent)) { + if (isList(*parent)) return parent; if (!firstNode) firstNode = parent; @@ -127,12 +123,13 @@ static RenderListItem* nextListItem(const Node* listNode, const RenderListItem* const Node* current = item ? item->node() : listNode; ASSERT(current); - current = ElementTraversal::nextIncludingPseudo(*current, listNode); + ASSERT(!current->document().childNeedsDistributionRecalc()); + current = NodeRenderingTraversal::next(current, listNode); while (current) { - if (isList(current)) { + if (isList(*current)) { // We've found a nested, independent list: nothing to do here. - current = ElementTraversal::nextIncludingPseudoSkippingChildren(*current, listNode); + current = NodeRenderingTraversal::next(current, listNode); continue; } @@ -141,7 +138,7 @@ static RenderListItem* nextListItem(const Node* listNode, const RenderListItem* return toRenderListItem(renderer); // FIXME: Can this be optimized to skip the children of the elements without a renderer? - current = ElementTraversal::nextIncludingPseudo(*current, listNode); + current = NodeRenderingTraversal::next(current, listNode); } return 0; @@ -152,7 +149,8 @@ static RenderListItem* previousListItem(const Node* listNode, const RenderListIt { Node* current = item->node(); ASSERT(current); - for (current = ElementTraversal::previousIncludingPseudo(*current, listNode); current; current = ElementTraversal::previousIncludingPseudo(*current, listNode)) { + ASSERT(!current->document().childNeedsDistributionRecalc()); + for (current = NodeRenderingTraversal::previous(current, listNode); current && current != listNode; current = NodeRenderingTraversal::previous(current, listNode)) { RenderObject* renderer = current->renderer(); if (!renderer || (renderer && !renderer->isListItem())) continue; @@ -165,7 +163,7 @@ static RenderListItem* previousListItem(const Node* listNode, const RenderListIt // be a list item itself. We need to examine it, so we do this to counteract // the previousIncludingPseudo() that will be done by the loop. if (otherList) - current = ElementTraversal::nextIncludingPseudo(*otherList); + current = NodeRenderingTraversal::next(otherList, listNode); } return 0; } @@ -195,7 +193,7 @@ inline int RenderListItem::calcValue() const return m_explicitValue; Node* list = enclosingList(this); - HTMLOListElement* oListElement = (list && list->hasTagName(olTag)) ? toHTMLOListElement(list) : 0; + HTMLOListElement* oListElement = isHTMLOListElement(list) ? toHTMLOListElement(list) : 0; int valueStep = 1; if (oListElement && oListElement->isReversed()) valueStep = -1; @@ -243,7 +241,7 @@ static RenderObject* getParentOfFirstLineBox(RenderBlockFlow* curr, RenderObject break; if (curr->isListItem() && inQuirksMode && currChild->node() && - (currChild->node()->hasTagName(ulTag)|| currChild->node()->hasTagName(olTag))) + (isHTMLUListElement(*currChild->node()) || isHTMLOListElement(*currChild->node()))) break; RenderObject* lineBox = getParentOfFirstLineBox(toRenderBlockFlow(currChild), marker); @@ -259,65 +257,82 @@ void RenderListItem::updateValue() if (!m_hasExplicitValue) { m_isValueUpToDate = false; if (m_marker) - m_marker->setNeedsLayoutAndPrefWidthsRecalc(); + m_marker->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } } static RenderObject* firstNonMarkerChild(RenderObject* parent) { - RenderObject* result = parent->firstChild(); + RenderObject* result = parent->slowFirstChild(); while (result && result->isListMarker()) result = result->nextSibling(); return result; } -void RenderListItem::updateMarkerLocation() +void RenderListItem::updateMarkerLocationAndInvalidateWidth() { - // Sanity check the location of our marker. - if (m_marker) { - RenderObject* markerParent = m_marker->parent(); - RenderObject* lineBoxParent = getParentOfFirstLineBox(this, m_marker); - if (!lineBoxParent) { - // If the marker is currently contained inside an anonymous box, - // then we are the only item in that anonymous box (since no line box - // parent was found). It's ok to just leave the marker where it is - // in this case. - if (markerParent && markerParent->isAnonymousBlock()) - lineBoxParent = markerParent; - else - lineBoxParent = this; - } + ASSERT(m_marker); + + // FIXME: We should not modify the structure of the render tree + // during layout. crbug.com/370461 + DeprecatedDisableModifyRenderTreeStructureAsserts disabler; + // Removing and adding the marker can trigger repainting in + // containers other than ourselves, so we need to disable LayoutState. + ForceHorriblySlowRectMapping slowRectMapping(*this); + if (updateMarkerLocation()) { + // If the marker is inside we need to redo the preferred width calculations + // as the size of the item now includes the size of the list marker. + if (m_marker->isInside()) + containingBlock()->updateLogicalWidth(); + } +} - if (markerParent != lineBoxParent || m_marker->preferredLogicalWidthsDirty()) { - // Removing and adding the marker can trigger repainting in - // containers other than ourselves, so we need to disable LayoutState. - LayoutStateDisabler layoutStateDisabler(view()); - updateFirstLetter(); - m_marker->remove(); - if (markerParent) - markerParent->dirtyLinesFromChangedChild(m_marker); - if (!lineBoxParent) - lineBoxParent = this; - lineBoxParent->addChild(m_marker, firstNonMarkerChild(lineBoxParent)); - m_marker->updateMarginsAndContent(); - // If markerParent is an anonymous block that has lost all its children, destroy it. - if (markerParent && markerParent->isAnonymousBlock() && !markerParent->firstChild() && !toRenderBlock(markerParent)->continuation()) - markerParent->destroy(); - - // If the marker is inside we need to redo the preferred width calculations - // as the size of the item now includes the size of the list marker. - if (m_marker->isInside()) - containingBlock()->updateLogicalWidth(); - } +bool RenderListItem::updateMarkerLocation() +{ + ASSERT(m_marker); + RenderObject* markerParent = m_marker->parent(); + RenderObject* lineBoxParent = getParentOfFirstLineBox(this, m_marker); + if (!lineBoxParent) { + // If the marker is currently contained inside an anonymous box, then we + // are the only item in that anonymous box (since no line box parent was + // found). It's ok to just leave the marker where it is in this case. + if (markerParent && markerParent->isAnonymousBlock()) + lineBoxParent = markerParent; + else + lineBoxParent = this; + } + + if (markerParent != lineBoxParent) { + updateFirstLetter(); + m_marker->remove(); + // FIXME(crbug.com/391009): Investigate whether this call is needed. + if (markerParent) + markerParent->dirtyLinesFromChangedChild(m_marker); + lineBoxParent->addChild(m_marker, firstNonMarkerChild(lineBoxParent)); + m_marker->updateMarginsAndContent(); + // If markerParent is an anonymous block with no children, destroy it. + if (markerParent && markerParent->isAnonymousBlock() && !toRenderBlock(markerParent)->firstChild() && !toRenderBlock(markerParent)->continuation()) + markerParent->destroy(); + return true; } + + return false; } void RenderListItem::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); - updateMarkerLocation(); + if (m_marker) { + // The marker must be autosized before calling + // updateMarkerLocationAndInvalidateWidth. It cannot be done in the + // parent's beginLayout because it is not yet in the render tree. + if (FastTextAutosizer* textAutosizer = document().fastTextAutosizer()) + textAutosizer->inflateListItem(this, m_marker); + + updateMarkerLocationAndInvalidateWidth(); + } + RenderBlockFlow::layout(); } @@ -340,18 +355,17 @@ void RenderListItem::positionListMarker() bool adjustOverflow = false; LayoutUnit markerLogicalLeft; - RootInlineBox* root = m_marker->inlineBoxWrapper()->root(); + RootInlineBox& root = m_marker->inlineBoxWrapper()->root(); bool hitSelfPaintingLayer = false; - RootInlineBox* rootBox = m_marker->inlineBoxWrapper()->root(); - LayoutUnit lineTop = rootBox->lineTop(); - LayoutUnit lineBottom = rootBox->lineBottom(); + LayoutUnit lineTop = root.lineTop(); + LayoutUnit lineBottom = root.lineBottom(); // FIXME: Need to account for relative positioning in the layout overflow. if (style()->isLeftToRightDirection()) { LayoutUnit leftLineOffset = logicalLeftOffsetForLine(blockOffset, logicalLeftOffsetForLine(blockOffset, false), false); markerLogicalLeft = leftLineOffset - lineOffset - paddingStart() - borderStart() + m_marker->marginStart(); - m_marker->inlineBoxWrapper()->adjustLineDirectionPosition(markerLogicalLeft - markerOldLogicalLeft); + m_marker->inlineBoxWrapper()->adjustLineDirectionPosition((markerLogicalLeft - markerOldLogicalLeft).toFloat()); for (InlineFlowBox* box = m_marker->inlineBoxWrapper()->parent(); box; box = box->parent()) { LayoutRect newLogicalVisualOverflowRect = box->logicalVisualOverflowRect(lineTop, lineBottom); LayoutRect newLogicalLayoutOverflowRect = box->logicalLayoutOverflowRect(lineTop, lineBottom); @@ -374,7 +388,7 @@ void RenderListItem::positionListMarker() } else { LayoutUnit rightLineOffset = logicalRightOffsetForLine(blockOffset, logicalRightOffsetForLine(blockOffset, false), false); markerLogicalLeft = rightLineOffset - lineOffset + paddingStart() + borderStart() + m_marker->marginEnd(); - m_marker->inlineBoxWrapper()->adjustLineDirectionPosition(markerLogicalLeft - markerOldLogicalLeft); + m_marker->inlineBoxWrapper()->adjustLineDirectionPosition((markerLogicalLeft - markerOldLogicalLeft).toFloat()); for (InlineFlowBox* box = m_marker->inlineBoxWrapper()->parent(); box; box = box->parent()) { LayoutRect newLogicalVisualOverflowRect = box->logicalVisualOverflowRect(lineTop, lineBottom); LayoutRect newLogicalLayoutOverflowRect = box->logicalLayoutOverflowRect(lineTop, lineBottom); @@ -437,33 +451,10 @@ const String& RenderListItem::markerText() const return nullAtom.string(); } -String RenderListItem::markerTextWithSuffix() const -{ - if (!m_marker) - return String(); - - // Append the suffix for the marker in the right place depending - // on the direction of the text (right-to-left or left-to-right). - - const String& markerText = m_marker->text(); - const String markerSuffix = m_marker->suffix(); - StringBuilder result; - - if (!m_marker->style()->isLeftToRightDirection()) - result.append(markerSuffix); - - result.append(markerText); - - if (m_marker->style()->isLeftToRightDirection()) - result.append(markerSuffix); - - return result.toString(); -} - void RenderListItem::explicitValueChanged() { if (m_marker) - m_marker->setNeedsLayoutAndPrefWidthsRecalc(); + m_marker->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); Node* listNode = enclosingList(this); for (RenderListItem* item = this; item; item = nextListItem(listNode, item)) item->updateValue(); @@ -492,6 +483,13 @@ void RenderListItem::clearExplicitValue() explicitValueChanged(); } +void RenderListItem::setNotInList(bool notInList) +{ + m_notInList = notInList; + if (m_marker) + updateMarkerLocation(); +} + static RenderListItem* previousOrNextItem(bool isListReversed, Node* list, RenderListItem* item) { return isListReversed ? previousListItem(list, item) : nextListItem(list, item); @@ -499,18 +497,28 @@ static RenderListItem* previousOrNextItem(bool isListReversed, Node* list, Rende void RenderListItem::updateListMarkerNumbers() { + // If distribution recalc is needed, updateListMarkerNumber will be re-invoked + // after distribution is calculated. + if (node()->document().childNeedsDistributionRecalc()) + return; + Node* listNode = enclosingList(this); - // The list node can be the shadow root which has no renderer. ASSERT(listNode); - if (!listNode) - return; bool isListReversed = false; - HTMLOListElement* oListElement = (listNode && listNode->hasTagName(olTag)) ? toHTMLOListElement(listNode) : 0; + HTMLOListElement* oListElement = isHTMLOListElement(listNode) ? toHTMLOListElement(listNode) : 0; if (oListElement) { oListElement->itemCountChanged(); isListReversed = oListElement->isReversed(); } + + // FIXME: The n^2 protection below doesn't help if the elements were inserted after the + // the list had already been displayed. + + // Avoid an O(n^2) walk over the children below when they're all known to be attaching. + if (listNode->needsAttach()) + return; + for (RenderListItem* item = previousOrNextItem(isListReversed, listNode, this); item; item = previousOrNextItem(isListReversed, listNode, item)) { if (!item->m_isValueUpToDate) { // If an item has been marked for update before, we can safely diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderListItem.h b/chromium/third_party/WebKit/Source/core/rendering/RenderListItem.h index 76f6087ea4b..ca46d46bf42 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderListItem.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderListItem.h @@ -42,40 +42,41 @@ public: void setExplicitValue(int value); void clearExplicitValue(); - void setNotInList(bool notInList) { m_notInList = notInList; } + void setNotInList(bool); bool notInList() const { return m_notInList; } const String& markerText() const; - String markerTextWithSuffix() const; void updateListMarkerNumbers(); - void updateMarkerLocation(); static void updateItemValuesForOrderedList(const HTMLOListElement*); static unsigned itemCountForOrderedList(const HTMLOListElement*); + bool isEmpty() const; + private: - virtual const char* renderName() const { return "RenderListItem"; } + virtual const char* renderName() const OVERRIDE { return "RenderListItem"; } - virtual bool isListItem() const { return true; } + virtual bool isListItem() const OVERRIDE { return true; } - virtual void willBeDestroyed(); + virtual void willBeDestroyed() OVERRIDE; virtual void insertedIntoTree() OVERRIDE; virtual void willBeRemovedFromTree() OVERRIDE; - virtual bool isEmpty() const; - virtual void paint(PaintInfo&, const LayoutPoint&); + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; - virtual void layout(); + virtual void layout() OVERRIDE; - virtual bool supportsPartialLayout() const OVERRIDE { return false; } + // Returns true if we re-attached and updated the location of the marker. + bool updateMarkerLocation(); + void updateMarkerLocationAndInvalidateWidth(); void positionListMarker(); - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; - virtual void addOverflowFromChildren(); + virtual void addOverflowFromChildren() OVERRIDE; inline int calcValue() const; void updateValueNow() const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderListMarker.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderListMarker.cpp index f05497493e5..492c3620d2f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderListMarker.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderListMarker.cpp @@ -28,7 +28,6 @@ #include "core/dom/Document.h" #include "core/fetch/ImageResource.h" #include "core/rendering/GraphicsContextAnnotator.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderListItem.h" #include "core/rendering/RenderView.h" @@ -1078,10 +1077,10 @@ RenderListMarker* RenderListMarker::createAnonymous(RenderListItem* item) return renderer; } -void RenderListMarker::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) +void RenderListMarker::styleWillChange(StyleDifference diff, const RenderStyle& newStyle) { - if (style() && (newStyle->listStylePosition() != style()->listStylePosition() || newStyle->listStyleType() != style()->listStyleType())) - setNeedsLayoutAndPrefWidthsRecalc(); + if (style() && (newStyle.listStylePosition() != style()->listStylePosition() || newStyle.listStyleType() != style()->listStyleType())) + setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); RenderBox::styleWillChange(diff, newStyle); } @@ -1116,11 +1115,11 @@ LayoutRect RenderListMarker::localSelectionRect() InlineBox* box = inlineBoxWrapper(); if (!box) return LayoutRect(LayoutPoint(), size()); - RootInlineBox* root = m_inlineBoxWrapper->root(); - LayoutUnit newLogicalTop = root->block()->style()->isFlippedBlocksWritingMode() ? m_inlineBoxWrapper->logicalBottom() - root->selectionBottom() : root->selectionTop() - m_inlineBoxWrapper->logicalTop(); - if (root->block()->style()->isHorizontalWritingMode()) - return LayoutRect(0, newLogicalTop, width(), root->selectionHeight()); - return LayoutRect(newLogicalTop, 0, root->selectionHeight(), height()); + RootInlineBox& root = inlineBoxWrapper()->root(); + LayoutUnit newLogicalTop = root.block().style()->isFlippedBlocksWritingMode() ? inlineBoxWrapper()->logicalBottom() - root.selectionBottom() : root.selectionTop() - inlineBoxWrapper()->logicalTop(); + if (root.block().style()->isHorizontalWritingMode()) + return LayoutRect(0, newLogicalTop, width(), root.selectionHeight()); + return LayoutRect(newLogicalTop, 0, root.selectionHeight(), height()); } void RenderListMarker::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) @@ -1136,7 +1135,6 @@ void RenderListMarker::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffse LayoutPoint boxOrigin(paintOffset + location()); LayoutRect overflowRect(visualOverflowRect()); overflowRect.moveBy(boxOrigin); - overflowRect.inflate(maximalOutlineSize(paintInfo.phase)); if (!paintInfo.rect.intersects(pixelSnappedIntRect(overflowRect))) return; @@ -1301,21 +1299,19 @@ void RenderListMarker::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffse } const UChar suffix = listMarkerSuffix(type, m_listItem->value()); + UChar suffixStr[2] = { + style()->isLeftToRightDirection() ? suffix : ' ', + style()->isLeftToRightDirection() ? ' ' : suffix + }; + TextRun suffixRun = RenderBlockFlow::constructTextRun(this, font, suffixStr, 2, style(), style()->direction()); + TextRunPaintInfo suffixRunInfo(suffixRun); + suffixRunInfo.bounds = marker; + if (style()->isLeftToRightDirection()) { context->drawText(font, textRunPaintInfo, textOrigin); - - UChar suffixSpace[2] = { suffix, ' ' }; - TextRun suffixRun = RenderBlockFlow::constructTextRun(this, font, suffixSpace, 2, style()); - TextRunPaintInfo suffixRunInfo(suffixRun); - suffixRunInfo.bounds = marker; context->drawText(font, suffixRunInfo, textOrigin + IntSize(font.width(textRun), 0)); } else { - UChar spaceSuffix[2] = { ' ', suffix }; - TextRun suffixRun = RenderBlockFlow::constructTextRun(this, font, spaceSuffix, 2, style()); - TextRunPaintInfo suffixRunInfo(suffixRun); - suffixRunInfo.bounds = marker; context->drawText(font, suffixRunInfo, textOrigin); - context->drawText(font, textRunPaintInfo, textOrigin + IntSize(font.width(suffixRun), 0)); } } @@ -1325,7 +1321,6 @@ void RenderListMarker::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); if (isImage()) { updateMarginsAndContent(); setWidth(m_image->imageSize(this, style()->effectiveZoom()).width()); @@ -1355,9 +1350,9 @@ void RenderListMarker::imageChanged(WrappedImagePtr o, const IntRect*) return; if (width() != m_image->imageSize(this, style()->effectiveZoom()).width() || height() != m_image->imageSize(this, style()->effectiveZoom()).height() || m_image->errorOccurred()) - setNeedsLayoutAndPrefWidthsRecalc(); + setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); else - repaint(); + paintInvalidationForWholeRenderer(); } void RenderListMarker::updateMarginsAndContent() @@ -1379,7 +1374,9 @@ void RenderListMarker::updateContent() // 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. int bulletWidth = style()->fontMetrics().ascent() / 2; - m_image->setContainerSizeForRenderer(this, IntSize(bulletWidth, bulletWidth), style()->effectiveZoom()); + IntSize defaultBulletSize(bulletWidth, bulletWidth); + IntSize imageSize = calculateImageIntrinsicDimensions(m_image.get(), defaultBulletSize, DoNotScaleByEffectiveZoom); + m_image->setContainerSizeForRenderer(this, imageSize, style()->effectiveZoom()); return; } @@ -1583,7 +1580,7 @@ void RenderListMarker::computePreferredLogicalWidths() else { LayoutUnit itemWidth = font.width(m_text); UChar suffixSpace[2] = { listMarkerSuffix(type, m_listItem->value()), ' ' }; - LayoutUnit suffixSpaceWidth = font.width(RenderBlockFlow::constructTextRun(this, font, suffixSpace, 2, style())); + LayoutUnit suffixSpaceWidth = font.width(RenderBlockFlow::constructTextRun(this, font, suffixSpace, 2, style(), style()->direction())); logicalWidth = itemWidth + suffixSpaceWidth; } break; @@ -1809,7 +1806,7 @@ IntRect RenderListMarker::getRelativeMarkerRect() const Font& font = style()->font(); int itemWidth = font.width(m_text); UChar suffixSpace[2] = { listMarkerSuffix(type, m_listItem->value()), ' ' }; - int suffixSpaceWidth = font.width(RenderBlockFlow::constructTextRun(this, font, suffixSpace, 2, style())); + int suffixSpaceWidth = font.width(RenderBlockFlow::constructTextRun(this, font, suffixSpace, 2, style(), style()->direction())); relativeRect = IntRect(0, 0, itemWidth + suffixSpaceWidth, font.fontMetrics().height()); } @@ -1826,25 +1823,24 @@ void RenderListMarker::setSelectionState(SelectionState state) // The selection state for our containing block hierarchy is updated by the base class call. RenderBox::setSelectionState(state); - if (m_inlineBoxWrapper && canUpdateSelectionOnRootLineBoxes()) - if (RootInlineBox* root = m_inlineBoxWrapper->root()) - root->setHasSelectedChildren(state != SelectionNone); + if (inlineBoxWrapper() && canUpdateSelectionOnRootLineBoxes()) + inlineBoxWrapper()->root().setHasSelectedChildren(state != SelectionNone); } -LayoutRect RenderListMarker::selectionRectForRepaint(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent) +LayoutRect RenderListMarker::selectionRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, bool clipToVisibleContent) { ASSERT(!needsLayout()); if (selectionState() == SelectionNone || !inlineBoxWrapper()) return LayoutRect(); - RootInlineBox* root = inlineBoxWrapper()->root(); - LayoutRect rect(0, root->selectionTop() - y(), width(), root->selectionHeight()); + RootInlineBox& root = inlineBoxWrapper()->root(); + LayoutRect rect(0, root.selectionTop() - y(), width(), root.selectionHeight()); if (clipToVisibleContent) - computeRectForRepaint(repaintContainer, rect); + mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect); else - rect = localToContainerQuad(FloatRect(rect), repaintContainer).enclosingBoundingBox(); + rect = localToContainerQuad(FloatRect(rect), paintInvalidationContainer).enclosingBoundingBox(); return rect; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderListMarker.h b/chromium/third_party/WebKit/Source/core/rendering/RenderListMarker.h index d0002ffb973..278626a3c5b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderListMarker.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderListMarker.h @@ -49,34 +49,34 @@ public: private: RenderListMarker(RenderListItem*); - virtual const char* renderName() const { return "RenderListMarker"; } + virtual const char* renderName() const OVERRIDE { return "RenderListMarker"; } virtual void computePreferredLogicalWidths() OVERRIDE; - virtual bool isListMarker() const { return true; } + virtual bool isListMarker() const OVERRIDE { return true; } - virtual void paint(PaintInfo&, const LayoutPoint&); + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; - virtual void layout(); + virtual void layout() OVERRIDE; - virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) OVERRIDE; - virtual InlineBox* createInlineBox(); + virtual InlineBox* createInlineBox() OVERRIDE; - virtual LayoutUnit lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const; - virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const; + virtual LayoutUnit lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const OVERRIDE; + virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const OVERRIDE; - bool isImage() const; + virtual bool isImage() const OVERRIDE; bool isText() const { return !isImage(); } - virtual void setSelectionState(SelectionState); - virtual LayoutRect selectionRectForRepaint(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent = true) OVERRIDE; - virtual bool canBeSelectionLeaf() const { return true; } + virtual void setSelectionState(SelectionState) OVERRIDE; + virtual LayoutRect selectionRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, bool clipToVisibleContent = true) OVERRIDE; + virtual bool canBeSelectionLeaf() const OVERRIDE { return true; } void updateMargins(); void updateContent(); - virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleWillChange(StyleDifference, const RenderStyle& newStyle) OVERRIDE; + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; IntRect getRelativeMarkerRect(); LayoutRect localSelectionRect(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMarquee.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderMarquee.cpp index a40fed1583d..4b1e9a20c00 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMarquee.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderMarquee.cpp @@ -46,12 +46,13 @@ #include "core/rendering/RenderMarquee.h" -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/html/HTMLMarqueeElement.h" #include "core/frame/FrameView.h" #include "core/frame/UseCounter.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderView.h" +#include "platform/LengthFunctions.h" using namespace std; @@ -172,7 +173,7 @@ void RenderMarquee::start() m_stopped = false; } - m_timer.startRepeating(speed() * 0.001); + m_timer.startRepeating(speed() * 0.001, FROM_HERE); } void RenderMarquee::suspend() @@ -194,8 +195,11 @@ void RenderMarquee::updateMarqueePosition() EMarqueeBehavior behavior = style()->marqueeBehavior(); m_start = computePosition(direction(), behavior == MALTERNATE); m_end = computePosition(reverseDirection(), behavior == MALTERNATE || behavior == MSLIDE); - if (!m_stopped) + if (!m_stopped) { + // Hits in compositing/overflow/do-not-repaint-if-scrolling-composited-layers.html during layout. + DisableCompositingQueryAsserts disabler; start(); + } } } @@ -215,7 +219,7 @@ const char* RenderMarquee::renderName() const void RenderMarquee::styleDidChange(StyleDifference difference, const RenderStyle* oldStyle) { - RenderBlock::styleDidChange(difference, oldStyle); + RenderBlockFlow::styleDidChange(difference, oldStyle); RenderStyle* s = style(); @@ -248,20 +252,20 @@ void RenderMarquee::styleDidChange(StyleDifference difference, const RenderStyle if (speed() != marqueeSpeed()) { m_speed = marqueeSpeed(); if (m_timer.isActive()) - m_timer.startRepeating(speed() * 0.001); + m_timer.startRepeating(speed() * 0.001, FROM_HERE); } // Check the loop count to see if we should now stop. bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops); if (activate && !m_timer.isActive()) - setNeedsLayout(); + setNeedsLayoutAndFullPaintInvalidation(); else if (!activate && m_timer.isActive()) m_timer.stop(); } -void RenderMarquee::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight) +void RenderMarquee::layoutBlock(bool relayoutChildren) { - RenderBlockFlow::layoutBlock(relayoutChildren, pageLogicalHeight); + RenderBlockFlow::layoutBlock(relayoutChildren); updateMarqueePosition(); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMarquee.h b/chromium/third_party/WebKit/Source/core/rendering/RenderMarquee.h index f69801dd44f..a089b234697 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMarquee.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderMarquee.h @@ -52,8 +52,6 @@ namespace WebCore { -class RenderLayer; - // This class handles the auto-scrolling for <marquee> class RenderMarquee FINAL : public RenderBlockFlow { public: @@ -83,15 +81,13 @@ public: void timerFired(); private: - virtual const char* renderName() const OVERRIDE FINAL; - - virtual bool isMarquee() const OVERRIDE FINAL { return true; } + virtual const char* renderName() const OVERRIDE; - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE FINAL; + virtual bool isMarquee() const OVERRIDE { return true; } - virtual void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0) OVERRIDE FINAL; + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; - virtual bool supportsPartialLayout() const OVERRIDE { return false; } + virtual void layoutBlock(bool relayoutChildren) OVERRIDE; int m_currentLoop; int m_totalLoops; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMedia.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderMedia.cpp index aacc6ae38a9..0062b292055 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMedia.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderMedia.cpp @@ -28,8 +28,6 @@ #include "core/rendering/RenderMedia.h" #include "core/html/HTMLMediaElement.h" -#include "core/rendering/LayoutRectRecorder.h" -#include "core/rendering/RenderFlowThread.h" #include "core/rendering/RenderView.h" namespace WebCore { @@ -51,7 +49,6 @@ HTMLMediaElement* RenderMedia::mediaElement() const void RenderMedia::layout() { - LayoutRectRecorder recorder(*this); LayoutSize oldSize = contentBoxRect().size(); RenderImage::layout(); @@ -61,30 +58,17 @@ void RenderMedia::layout() return; bool controlsNeedLayout = controlsRenderer->needsLayout(); - // If the region chain has changed we also need to relayout the controls to update the region box info. - // FIXME: We can do better once we compute region box info for RenderReplaced, not only for RenderBlock. - const RenderFlowThread* flowThread = flowThreadContainingBlock(); - if (flowThread && !controlsNeedLayout) { - if (flowThread->pageLogicalSizeChanged()) - controlsNeedLayout = true; - } - LayoutSize newSize = contentBoxRect().size(); if (newSize == oldSize && !controlsNeedLayout) return; - // When calling layout() on a child node, a parent must either push a LayoutStateMaintainter, or - // instantiate LayoutStateDisabler. Since using a LayoutStateMaintainer is slightly more efficient, - // and this method will be called many times per second during playback, use a LayoutStateMaintainer: - LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode()); + LayoutState state(*this, locationOffset()); controlsRenderer->setLocation(LayoutPoint(borderLeft(), borderTop()) + LayoutSize(paddingLeft(), paddingTop())); controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed)); controlsRenderer->style()->setWidth(Length(newSize.width(), Fixed)); controlsRenderer->forceLayout(); clearNeedsLayout(); - - statePusher.pop(); } void RenderMedia::paintReplaced(PaintInfo&, const LayoutPoint&) diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMedia.h b/chromium/third_party/WebKit/Source/core/rendering/RenderMedia.h index ada064b59c0..c970b2909db 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMedia.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderMedia.h @@ -40,27 +40,33 @@ public: RenderObject* firstChild() const { ASSERT(children() == virtualChildren()); return children()->firstChild(); } RenderObject* lastChild() const { ASSERT(children() == virtualChildren()); return children()->lastChild(); } + // If you have a RenderMedia, use firstChild or lastChild instead. + void slowFirstChild() const WTF_DELETED_FUNCTION; + void slowLastChild() const WTF_DELETED_FUNCTION; + const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } HTMLMediaElement* mediaElement() const; protected: - virtual void layout(); + virtual void layout() OVERRIDE; private: virtual RenderObjectChildList* virtualChildren() OVERRIDE FINAL { return children(); } virtual const RenderObjectChildList* virtualChildren() const OVERRIDE FINAL { return children(); } + virtual LayerType layerTypeRequired() const OVERRIDE { return NormalLayer; } + // FIXME: RenderMedia::layout makes assumptions about what children are allowed // so we can't support generated content. virtual bool canHaveGeneratedChildren() const OVERRIDE FINAL { return false; } virtual bool canHaveChildren() const OVERRIDE FINAL { return true; } - virtual const char* renderName() const { return "RenderMedia"; } + virtual const char* renderName() const OVERRIDE { return "RenderMedia"; } virtual bool isMedia() const OVERRIDE FINAL { return true; } virtual bool isImage() const OVERRIDE FINAL { return false; } - virtual void paintReplaced(PaintInfo&, const LayoutPoint&); + virtual void paintReplaced(PaintInfo&, const LayoutPoint&) OVERRIDE; RenderObjectChildList m_children; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMediaControlElements.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderMediaControlElements.cpp index da2babc48d5..bdf6b1367c8 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMediaControlElements.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderMediaControlElements.cpp @@ -29,7 +29,7 @@ #include "core/rendering/RenderMediaControlElements.h" -#include "core/rendering/LayoutRectRecorder.h" +#include "core/frame/DeprecatedScheduleStyleRecalcDuringLayout.h" #include "core/rendering/RenderView.h" namespace WebCore { @@ -41,17 +41,16 @@ RenderTextTrackContainerElement::RenderTextTrackContainerElement(Element* elemen void RenderTextTrackContainerElement::layout() { - LayoutRectRecorder recorder(*this); - RenderBlock::layout(); + RenderBlockFlow::layout(); if (style()->display() == NONE) return; ASSERT(mediaControlElementType(node()) == MediaTextTrackDisplayContainer); - LayoutStateDisabler layoutStateDisabler(view()); + DeprecatedScheduleStyleRecalcDuringLayout marker(node()->document().lifecycle()); + + ForceHorriblySlowRectMapping slowRectMapping(*this); static_cast<MediaControlTextTrackContainerElement*>(node())->updateSizes(); } - } // namespace WebCore - diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMediaControlElements.h b/chromium/third_party/WebKit/Source/core/rendering/RenderMediaControlElements.h index 90a7d5ea1f2..b22aa736013 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMediaControlElements.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderMediaControlElements.h @@ -39,8 +39,7 @@ public: RenderTextTrackContainerElement(Element*); private: - virtual void layout(); - virtual bool supportsPartialLayout() const OVERRIDE { return false; } + virtual void layout() OVERRIDE; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMediaControls.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderMediaControls.cpp index 13d1620367a..90b28aa442f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMediaControls.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderMediaControls.cpp @@ -106,7 +106,7 @@ static bool paintMediaPlayButton(RenderObject* object, const PaintInfo& paintInf if (!hasSource(mediaElement)) return paintMediaButton(paintInfo.context, rect, mediaPlayDisabled); - return paintMediaButton(paintInfo.context, rect, mediaElement->canPlay() ? mediaPlay : mediaPause); + return paintMediaButton(paintInfo.context, rect, mediaControlElementType(object->node()) == MediaPlayButton ? mediaPlay : mediaPause); } static bool paintMediaOverlayPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) @@ -115,7 +115,7 @@ static bool paintMediaOverlayPlayButton(RenderObject* object, const PaintInfo& p if (!mediaElement) return false; - if (!hasSource(mediaElement) || !mediaElement->canPlay()) + if (!hasSource(mediaElement) || !mediaElement->togglePlayStateWillPlay()) return false; static Image* mediaOverlayPlay = platformResource("mediaplayerOverlayPlay"); @@ -133,9 +133,7 @@ static void paintRoundedSliderBackground(const IntRect& rect, const RenderStyle* int borderRadius = rect.height() / 2; IntSize radii(borderRadius, borderRadius); Color sliderBackgroundColor = Color(11, 11, 11); - context->save(); context->fillRoundedRect(rect, radii, radii, radii, radii, sliderBackgroundColor); - context->restore(); } static void paintSliderRangeHighlight(const IntRect& rect, const RenderStyle* style, GraphicsContext* context, int startPosition, int endPosition, Color startColor, Color endColor) @@ -156,10 +154,8 @@ static void paintSliderRangeHighlight(const IntRect& rect, const RenderStyle* st // Make sure the range width is bigger than border radius at the edges to retain rounded corners. if (startOffset < borderRadius && rangeWidth < borderRadius) rangeWidth = borderRadius; - if (endOffset < borderRadius && rangeWidth < borderRadius) { - startPosition -= borderRadius - rangeWidth; + if (endOffset < borderRadius && rangeWidth < borderRadius) rangeWidth = borderRadius; - } // Set rectangle to highlight range. IntRect highlightRect = rect; @@ -365,16 +361,11 @@ bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, R return paintMediaFullscreenButton(object, paintInfo, rect); case MediaOverlayPlayButton: return paintMediaOverlayPlayButton(object, paintInfo, rect); - case MediaVolumeSliderMuteButton: - case MediaSeekBackButton: - case MediaSeekForwardButton: case MediaVolumeSliderContainer: case MediaTimelineContainer: case MediaCurrentTimeDisplay: case MediaTimeRemainingDisplay: case MediaControlsPanel: - case MediaRewindButton: - case MediaReturnToRealtimeButton: case MediaStatusDisplay: case MediaHideClosedCaptionsButton: case MediaTextTrackDisplayContainer: diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMediaControls.h b/chromium/third_party/WebKit/Source/core/rendering/RenderMediaControls.h index 8f40830228b..f007d6490ff 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMediaControls.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderMediaControls.h @@ -34,7 +34,6 @@ namespace WebCore { struct PaintInfo; -class HTMLMediaElement; class IntRect; class RenderObject; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMenuList.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderMenuList.cpp index 57c8afc1cf8..f900e5885f0 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMenuList.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderMenuList.cpp @@ -25,26 +25,27 @@ #include "config.h" #include "core/rendering/RenderMenuList.h" -#include <math.h> -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/accessibility/AXMenuList.h" #include "core/accessibility/AXObjectCache.h" #include "core/css/CSSFontSelector.h" #include "core/css/resolver/StyleResolver.h" #include "core/dom/NodeRenderStyle.h" +#include "core/frame/FrameHost.h" +#include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/html/HTMLOptGroupElement.h" #include "core/html/HTMLOptionElement.h" #include "core/html/HTMLSelectElement.h" #include "core/page/Chrome.h" -#include "core/frame/Frame.h" -#include "core/frame/FrameView.h" -#include "core/page/Page.h" #include "core/rendering/RenderBR.h" #include "core/rendering/RenderScrollbar.h" #include "core/rendering/RenderTheme.h" #include "core/rendering/RenderView.h" #include "platform/fonts/FontCache.h" #include "platform/geometry/IntSize.h" +#include "platform/text/PlatformLocale.h" +#include <math.h> using namespace std; @@ -61,16 +62,21 @@ RenderMenuList::RenderMenuList(Element* element) , m_lastActiveIndex(-1) , m_popupIsVisible(false) { - ASSERT(element); - ASSERT(element->isHTMLElement()); - ASSERT(element->hasTagName(HTMLNames::selectTag)); + ASSERT(isHTMLSelectElement(element)); } RenderMenuList::~RenderMenuList() { if (m_popup) m_popup->disconnectClient(); - m_popup = 0; + m_popup = nullptr; +} + +// FIXME: Instead of this hack we should add a ShadowRoot to <select> with no insertion point +// to prevent children from rendering. +bool RenderMenuList::isChildAllowed(RenderObject* object, RenderStyle*) const +{ + return object->isAnonymous() && !object->isRenderFullScreen(); } void RenderMenuList::createInnerBlock() @@ -93,16 +99,13 @@ void RenderMenuList::adjustInnerStyle() RenderStyle* innerStyle = m_innerBlock->style(); innerStyle->setFlexGrow(1); innerStyle->setFlexShrink(1); - // min-width: 0; is needed for correct shrinking. - // FIXME: Remove this line when https://bugs.webkit.org/show_bug.cgi?id=111790 is fixed. - innerStyle->setMinWidth(Length(0, Fixed)); // Use margin:auto instead of align-items:center to get safe centering, i.e. // when the content overflows, treat it the same as align-items: flex-start. // But we only do that for the cases where html.css would otherwise use center. - if (style()->alignItems() == AlignCenter) { + if (style()->alignItems() == ItemPositionCenter) { innerStyle->setMarginTop(Length()); innerStyle->setMarginBottom(Length()); - innerStyle->setAlignSelf(AlignFlexStart); + innerStyle->setAlignSelf(ItemPositionFlexStart); } innerStyle->setPaddingLeft(Length(RenderTheme::theme().popupInternalPaddingLeft(style()), Fixed)); @@ -112,7 +115,7 @@ void RenderMenuList::adjustInnerStyle() if (m_optionStyle) { if ((m_optionStyle->direction() != innerStyle->direction() || m_optionStyle->unicodeBidi() != innerStyle->unicodeBidi())) - m_innerBlock->setNeedsLayoutAndPrefWidthsRecalc(); + m_innerBlock->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); innerStyle->setTextAlign(style()->isLeftToRightDirection() ? LEFT : RIGHT); innerStyle->setDirection(m_optionStyle->direction()); innerStyle->setUnicodeBidi(m_optionStyle->unicodeBidi()); @@ -160,13 +163,13 @@ void RenderMenuList::styleDidChange(StyleDifference diff, const RenderStyle* old void RenderMenuList::updateOptionsWidth() { float maxOptionWidth = 0; - const Vector<HTMLElement*>& listItems = selectElement()->listItems(); + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); int size = listItems.size(); FontCachePurgePreventer fontCachePurgePreventer; for (int i = 0; i < size; ++i) { HTMLElement* element = listItems[i]; - if (!element->hasTagName(optionTag)) + if (!isHTMLOptionElement(*element)) continue; String text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel(); @@ -175,7 +178,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 += minimumValueForLength(optionStyle->textIndent(), 0, view()); + optionWidth += minimumValueForLength(optionStyle->textIndent(), 0); if (!text.isEmpty()) optionWidth += style()->font().width(text); maxOptionWidth = max(maxOptionWidth, optionWidth); @@ -189,7 +192,7 @@ void RenderMenuList::updateOptionsWidth() m_optionsWidth = width; if (parent()) - setNeedsLayoutAndPrefWidthsRecalc(); + setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } void RenderMenuList::updateFromElement() @@ -199,29 +202,65 @@ void RenderMenuList::updateFromElement() m_optionsChanged = false; } - if (m_popupIsVisible) + if (m_popupIsVisible) { m_popup->updateFromElement(); - else - setTextFromOption(selectElement()->selectedIndex()); + } else { + if (selectElement()->suggestedIndex() >= 0) + setTextFromOption(selectElement()->suggestedIndex()); + else + setTextFromOption(selectElement()->selectedIndex()); + } } void RenderMenuList::setTextFromOption(int optionIndex) { HTMLSelectElement* select = selectElement(); - const Vector<HTMLElement*>& listItems = select->listItems(); - int size = listItems.size(); + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = select->listItems(); + const int size = listItems.size(); - int i = select->optionToListIndex(optionIndex); String text = emptyString(); - if (i >= 0 && i < size) { - Element* element = listItems[i]; - if (element->hasTagName(optionTag)) { - text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel(); - m_optionStyle = element->renderStyle(); + m_optionStyle.clear(); + + if (multiple()) { + unsigned selectedCount = 0; + int firstSelectedIndex = -1; + for (int i = 0; i < size; ++i) { + Element* element = listItems[i]; + if (!isHTMLOptionElement(*element)) + continue; + + if (toHTMLOptionElement(element)->selected()) { + if (++selectedCount == 1) + firstSelectedIndex = i; + } + } + + if (selectedCount == 1) { + ASSERT(0 <= firstSelectedIndex); + ASSERT(firstSelectedIndex < size); + HTMLOptionElement* selectedOptionElement = toHTMLOptionElement(listItems[firstSelectedIndex]); + ASSERT(selectedOptionElement->selected()); + text = selectedOptionElement->textIndentedToRespectGroupLabel(); + m_optionStyle = selectedOptionElement->renderStyle(); + } else { + Locale& locale = select->locale(); + String localizedNumberString = locale.convertToLocalizedNumber(String::number(selectedCount)); + text = locale.queryString(blink::WebLocalizedString::SelectMenuListText, localizedNumberString); + ASSERT(!m_optionStyle); + } + } else { + const int i = select->optionToListIndex(optionIndex); + if (i >= 0 && i < size) { + Element* element = listItems[i]; + if (isHTMLOptionElement(*element)) { + text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel(); + m_optionStyle = element->renderStyle(); + } } } setText(text.stripWhiteSpace()); + didUpdateActiveOption(optionIndex); } @@ -229,6 +268,9 @@ void RenderMenuList::setText(const String& s) { if (s.isEmpty()) { if (!m_buttonText || !m_buttonText->isBR()) { + // FIXME: We should not modify the structure of the render tree + // during layout. crbug.com/370462 + DeprecatedDisableModifyRenderTreeStructureAsserts disabler; if (m_buttonText) m_buttonText->destroy(); m_buttonText = new RenderBR(&document()); @@ -239,6 +281,9 @@ void RenderMenuList::setText(const String& s) if (m_buttonText && !m_buttonText->isBR()) m_buttonText->setText(s.impl(), true); else { + // FIXME: We should not modify the structure of the render tree + // during layout. crbug.com/370462 + DeprecatedDisableModifyRenderTreeStructureAsserts disabler; if (m_buttonText) m_buttonText->destroy(); m_buttonText = new RenderText(&document(), s.impl()); @@ -287,20 +332,21 @@ void RenderMenuList::computePreferredLogicalWidths() { m_minPreferredLogicalWidth = 0; m_maxPreferredLogicalWidth = 0; + RenderStyle* styleToUse = style(); - if (style()->width().isFixed() && style()->width().value() > 0) - m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->width().value()); + if (styleToUse->width().isFixed() && styleToUse->width().value() > 0) + m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->width().value()); else computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth); - if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) { - m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value())); - m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value())); + if (styleToUse->minWidth().isFixed() && styleToUse->minWidth().value() > 0) { + m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->minWidth().value())); + m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->minWidth().value())); } - if (style()->maxWidth().isFixed()) { - m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value())); - m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value())); + if (styleToUse->maxWidth().isFixed()) { + m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->maxWidth().value())); + m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->maxWidth().value())); } LayoutUnit toAdd = borderAndPaddingWidth(); @@ -315,7 +361,7 @@ void RenderMenuList::showPopup() if (m_popupIsVisible) return; - if (document().page()->chrome().hasOpenedPopup()) + if (document().frameHost()->chrome().hasOpenedPopup()) return; // Create m_innerBlock here so it ends up as the first child. @@ -323,7 +369,7 @@ void RenderMenuList::showPopup() // inside the showPopup call and it would fail. createInnerBlock(); if (!m_popup) - m_popup = document().page()->chrome().createPopupMenu(*document().frame(), this); + m_popup = document().frameHost()->chrome().createPopupMenu(*document().frame(), this); m_popupIsVisible = true; FloatQuad quad(localToAbsoluteQuad(FloatQuad(borderBoundingBox()))); @@ -385,35 +431,25 @@ void RenderMenuList::didUpdateActiveOption(int optionIndex) String RenderMenuList::itemText(unsigned listIndex) const { HTMLSelectElement* select = selectElement(); - const Vector<HTMLElement*>& listItems = select->listItems(); + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = select->listItems(); if (listIndex >= listItems.size()) return String(); String itemString; Element* element = listItems[listIndex]; - if (isHTMLOptGroupElement(element)) - itemString = toHTMLOptGroupElement(element)->groupLabelText(); - else if (element->hasTagName(optionTag)) - itemString = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel(); + if (isHTMLOptGroupElement(*element)) + itemString = toHTMLOptGroupElement(*element).groupLabelText(); + else if (isHTMLOptionElement(*element)) + itemString = toHTMLOptionElement(*element).textIndentedToRespectGroupLabel(); applyTextTransform(style(), itemString, ' '); return itemString; } -String RenderMenuList::itemLabel(unsigned) const -{ - return String(); -} - -String RenderMenuList::itemIcon(unsigned) const -{ - return String(); -} - String RenderMenuList::itemAccessibilityText(unsigned listIndex) const { // Allow the accessible name be changed if necessary. - const Vector<HTMLElement*>& listItems = selectElement()->listItems(); + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); if (listIndex >= listItems.size()) return String(); return listItems[listIndex]->fastGetAttribute(aria_labelAttr); @@ -421,7 +457,7 @@ String RenderMenuList::itemAccessibilityText(unsigned listIndex) const String RenderMenuList::itemToolTip(unsigned listIndex) const { - const Vector<HTMLElement*>& listItems = selectElement()->listItems(); + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); if (listIndex >= listItems.size()) return String(); return listItems[listIndex]->title(); @@ -429,16 +465,16 @@ String RenderMenuList::itemToolTip(unsigned listIndex) const bool RenderMenuList::itemIsEnabled(unsigned listIndex) const { - const Vector<HTMLElement*>& listItems = selectElement()->listItems(); + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); if (listIndex >= listItems.size()) return false; HTMLElement* element = listItems[listIndex]; - if (!element->hasTagName(optionTag)) + if (!isHTMLOptionElement(*element)) return false; bool groupEnabled = true; if (Element* parentElement = element->parentElement()) { - if (isHTMLOptGroupElement(parentElement)) + if (isHTMLOptGroupElement(*parentElement)) groupEnabled = !parentElement->isDisabledFormControl(); } if (!groupEnabled) @@ -449,7 +485,7 @@ bool RenderMenuList::itemIsEnabled(unsigned listIndex) const PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const { - const Vector<HTMLElement*>& listItems = selectElement()->listItems(); + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); if (listIndex >= listItems.size()) { // If we are making an out of bounds access, then we want to use the style // of a different option element (index 0). However, if there isn't an option element @@ -474,7 +510,7 @@ PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const void RenderMenuList::getItemBackgroundColor(unsigned listIndex, Color& itemBackgroundColor, bool& itemHasCustomBackgroundColor) const { - const Vector<HTMLElement*>& listItems = selectElement()->listItems(); + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); if (listIndex >= listItems.size()) { itemBackgroundColor = resolveColor(CSSPropertyBackgroundColor); itemHasCustomBackgroundColor = false; @@ -485,7 +521,7 @@ void RenderMenuList::getItemBackgroundColor(unsigned listIndex, Color& itemBackg Color backgroundColor; if (element->renderStyle()) backgroundColor = resolveColor(element->renderStyle(), CSSPropertyBackgroundColor); - itemHasCustomBackgroundColor = backgroundColor.isValid() && backgroundColor.alpha(); + itemHasCustomBackgroundColor = backgroundColor.alpha(); // If the item has an opaque background color, return that. if (!backgroundColor.hasAlpha()) { itemBackgroundColor = backgroundColor; @@ -511,32 +547,6 @@ PopupMenuStyle RenderMenuList::menuStyle() const s->display() == NONE, s->textIndent(), style()->direction(), isOverride(style()->unicodeBidi())); } -HostWindow* RenderMenuList::hostWindow() const -{ - return document().view()->hostWindow(); -} - -PassRefPtr<Scrollbar> RenderMenuList::createScrollbar(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, ScrollbarControlSize controlSize) -{ - RefPtr<Scrollbar> widget; - bool hasCustomScrollbarStyle = style()->hasPseudoStyle(SCROLLBAR); - if (hasCustomScrollbarStyle) - widget = RenderScrollbar::createCustomScrollbar(scrollableArea, orientation, this->node()); - else - widget = Scrollbar::create(scrollableArea, orientation, controlSize); - return widget.release(); -} - -int RenderMenuList::clientInsetLeft() const -{ - return 0; -} - -int RenderMenuList::clientInsetRight() const -{ - return 0; -} - LayoutUnit RenderMenuList::clientPaddingLeft() const { return paddingLeft() + m_innerBlock->paddingLeft(); @@ -576,23 +586,23 @@ void RenderMenuList::popupDidHide() bool RenderMenuList::itemIsSeparator(unsigned listIndex) const { - const Vector<HTMLElement*>& listItems = selectElement()->listItems(); - return listIndex < listItems.size() && listItems[listIndex]->hasTagName(hrTag); + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); + return listIndex < listItems.size() && isHTMLHRElement(*listItems[listIndex]); } bool RenderMenuList::itemIsLabel(unsigned listIndex) const { - const Vector<HTMLElement*>& listItems = selectElement()->listItems(); - return listIndex < listItems.size() && isHTMLOptGroupElement(listItems[listIndex]); + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); + return listIndex < listItems.size() && isHTMLOptGroupElement(*listItems[listIndex]); } bool RenderMenuList::itemIsSelected(unsigned listIndex) const { - const Vector<HTMLElement*>& listItems = selectElement()->listItems(); + const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems(); if (listIndex >= listItems.size()) return false; HTMLElement* element = listItems[listIndex]; - return element->hasTagName(optionTag) && toHTMLOptionElement(element)->selected(); + return isHTMLOptionElement(*element) && toHTMLOptionElement(*element).selected(); } void RenderMenuList::setTextFromItem(unsigned listIndex) @@ -600,9 +610,4 @@ void RenderMenuList::setTextFromItem(unsigned listIndex) setTextFromOption(selectElement()->listToOptionIndex(listIndex)); } -FontSelector* RenderMenuList::fontSelector() const -{ - return document().styleEngine()->fontSelector(); -} - } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMenuList.h b/chromium/third_party/WebKit/Source/core/rendering/RenderMenuList.h index 54561e0d673..b7dc98c965b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMenuList.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderMenuList.h @@ -54,39 +54,36 @@ public: private: HTMLSelectElement* selectElement() const; - virtual bool isMenuList() const { return true; } + virtual bool isMenuList() const OVERRIDE { return true; } + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; - virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); - virtual void removeChild(RenderObject*); - virtual bool createsAnonymousWrapper() const { return true; } + virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0) OVERRIDE; + virtual void removeChild(RenderObject*) OVERRIDE; + virtual bool createsAnonymousWrapper() const OVERRIDE { return true; } - virtual void updateFromElement(); + virtual void updateFromElement() OVERRIDE; - virtual LayoutRect controlClipRect(const LayoutPoint&) const; - virtual bool hasControlClip() const { return true; } + virtual LayoutRect controlClipRect(const LayoutPoint&) const OVERRIDE; + virtual bool hasControlClip() const OVERRIDE { return true; } virtual bool canHaveGeneratedChildren() const OVERRIDE { return false; } - virtual const char* renderName() const { return "RenderMenuList"; } + virtual const char* renderName() const OVERRIDE { return "RenderMenuList"; } virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE; virtual void computePreferredLogicalWidths() OVERRIDE; - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; // PopupMenuClient methods virtual void valueChanged(unsigned listIndex, bool fireOnChange = true) OVERRIDE; virtual void selectionChanged(unsigned, bool) OVERRIDE { } virtual void selectionCleared() OVERRIDE { } virtual String itemText(unsigned listIndex) const OVERRIDE; - virtual String itemLabel(unsigned listIndex) const OVERRIDE; - virtual String itemIcon(unsigned listIndex) const OVERRIDE; virtual String itemToolTip(unsigned listIndex) const OVERRIDE; virtual String itemAccessibilityText(unsigned listIndex) const OVERRIDE; virtual bool itemIsEnabled(unsigned listIndex) const OVERRIDE; virtual PopupMenuStyle itemStyle(unsigned listIndex) const OVERRIDE; virtual PopupMenuStyle menuStyle() const OVERRIDE; - virtual int clientInsetLeft() const OVERRIDE; - virtual int clientInsetRight() const OVERRIDE; virtual LayoutUnit clientPaddingLeft() const OVERRIDE; virtual LayoutUnit clientPaddingRight() const OVERRIDE; virtual int listSize() const OVERRIDE; @@ -95,15 +92,11 @@ private: virtual bool itemIsSeparator(unsigned listIndex) const OVERRIDE; virtual bool itemIsLabel(unsigned listIndex) const OVERRIDE; virtual bool itemIsSelected(unsigned listIndex) const OVERRIDE; - virtual bool valueShouldChangeOnHotTrack() const OVERRIDE { return true; } virtual void setTextFromItem(unsigned listIndex) OVERRIDE; virtual void listBoxSelectItem(int listIndex, bool allowMultiplySelections, bool shift, bool fireOnChangeNow = true) OVERRIDE; virtual bool multiple() const OVERRIDE; - virtual FontSelector* fontSelector() const OVERRIDE; - virtual HostWindow* hostWindow() const OVERRIDE; - virtual PassRefPtr<Scrollbar> createScrollbar(ScrollableArea*, ScrollbarOrientation, ScrollbarControlSize) OVERRIDE; - virtual bool hasLineIfEmpty() const { return true; } + virtual bool hasLineIfEmpty() const OVERRIDE { return true; } // Flexbox defines baselines differently than regular blocks. // For backwards compatibility, menulists need to do the regular block behavior. diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMeter.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderMeter.cpp index a4982a9bb70..1a26f7ac286 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMeter.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderMeter.cpp @@ -44,7 +44,7 @@ HTMLMeterElement* RenderMeter::meterElement() const { ASSERT(node()); - if (isHTMLMeterElement(node())) + if (isHTMLMeterElement(*node())) return toHTMLMeterElement(node()); ASSERT(node()->shadowHost()); @@ -79,7 +79,7 @@ double RenderMeter::valueRatio() const void RenderMeter::updateFromElement() { - repaint(); + paintInvalidationForWholeRenderer(); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMeter.h b/chromium/third_party/WebKit/Source/core/rendering/RenderMeter.h index d1f1e438aef..51ced2147e4 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMeter.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderMeter.h @@ -34,16 +34,14 @@ public: virtual ~RenderMeter(); HTMLMeterElement* meterElement() const; - virtual void updateFromElement(); + virtual void updateFromElement() OVERRIDE; private: virtual void updateLogicalWidth() OVERRIDE; virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE; - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - - virtual const char* renderName() const { return "RenderMeter"; } - virtual bool isMeter() const { return true; } + virtual const char* renderName() const OVERRIDE { return "RenderMeter"; } + virtual bool isMeter() const OVERRIDE { return true; } double valueRatio() const; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnBlock.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnBlock.cpp deleted file mode 100644 index 53c1fe86a66..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnBlock.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* - * 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 "core/rendering/RenderMultiColumnBlock.h" - -#include "core/rendering/RenderMultiColumnFlowThread.h" -#include "core/rendering/RenderMultiColumnSet.h" -#include "core/rendering/RenderView.h" - -using namespace std; - -namespace WebCore { - -RenderMultiColumnBlock::RenderMultiColumnBlock(Element* element) - : RenderBlockFlow(element) - , m_flowThread(0) - , m_columnCount(1) - , m_columnWidth(0) - , m_columnHeightAvailable(0) - , m_inBalancingPass(false) -{ -} - -void RenderMultiColumnBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) -{ - RenderBlock::styleDidChange(diff, oldStyle); - for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) - child->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK)); -} - -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::updateLogicalWidthAndColumnWidth() -{ - bool relayoutChildren = RenderBlock::updateLogicalWidthAndColumnWidth(); - LayoutUnit oldColumnWidth = m_columnWidth; - computeColumnCountAndWidth(); - if (m_columnWidth != oldColumnWidth) - relayoutChildren = true; - return relayoutChildren; -} - -void RenderMultiColumnBlock::checkForPaginationLogicalHeightChange(LayoutUnit& /*pageLogicalHeight*/, bool& /*pageLogicalHeightChanged*/, bool& /*hasSpecifiedPageLogicalHeight*/) -{ - // We don't actually update any of the variables. We just subclassed to adjust our column height. - updateLogicalHeight(); - m_columnHeightAvailable = max<LayoutUnit>(contentLogicalHeight(), 0); - setLogicalHeight(0); -} - -bool RenderMultiColumnBlock::relayoutForPagination(bool, LayoutUnit, LayoutStateMaintainer& statePusher) -{ - if (m_inBalancingPass || !requiresBalancing()) - return false; - m_inBalancingPass = true; // Prevent re-entering this method (and recursion into layout). - - bool needsRelayout; - bool neededRelayout = false; - bool firstPass = true; - do { - // Column heights may change here because of balancing. We may have to do multiple layout - // passes, depending on how the contents is fitted to the changed column heights. In most - // cases, laying out again twice or even just once will suffice. Sometimes we need more - // passes than that, though, but the number of retries should not exceed the number of - // columns, unless we have a bug. - needsRelayout = false; - for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) { - if (childBox != m_flowThread && childBox->isRenderMultiColumnSet()) { - RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(childBox); - if (multicolSet->calculateBalancedHeight(firstPass)) { - multicolSet->setChildNeedsLayout(MarkOnlyThis); - needsRelayout = true; - } - } - } - - if (needsRelayout) { - // Layout again. Column balancing resulted in a new height. - neededRelayout = true; - m_flowThread->setChildNeedsLayout(MarkOnlyThis); - setChildNeedsLayout(MarkOnlyThis); - if (firstPass) - statePusher.pop(); - layoutBlock(false); - } - firstPass = false; - } while (needsRelayout); - m_inBalancingPass = false; - return neededRelayout; -} - -void RenderMultiColumnBlock::addChild(RenderObject* newChild, RenderObject* beforeChild) -{ - if (!m_flowThread) { - m_flowThread = RenderMultiColumnFlowThread::createAnonymous(&document()); - m_flowThread->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK)); - RenderBlock::addChild(m_flowThread); - } - m_flowThread->addChild(newChild, beforeChild); -} - -RenderObject* RenderMultiColumnBlock::layoutSpecialExcludedChild(bool relayoutChildren, SubtreeLayoutScope& layoutScope) -{ - if (!m_flowThread) - return 0; - - // Update the dimensions of our regions before we lay out the flow thread. - // FIXME: Eventually this is going to get way more complicated, and we will be destroying regions - // instead of trying to keep them around. - bool shouldInvalidateRegions = false; - for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) { - if (childBox == m_flowThread) - continue; - - if (relayoutChildren || childBox->needsLayout()) { - if (!m_inBalancingPass && childBox->isRenderMultiColumnSet()) - toRenderMultiColumnSet(childBox)->prepareForLayout(); - shouldInvalidateRegions = true; - } - } - - if (shouldInvalidateRegions) - m_flowThread->invalidateRegions(); - - if (relayoutChildren) - layoutScope.setChildNeedsLayout(m_flowThread); - - setLogicalTopForChild(m_flowThread, borderBefore() + paddingBefore()); - m_flowThread->layoutIfNeeded(); - determineLogicalLeftPositionForChild(m_flowThread); - - return m_flowThread; -} - -const char* RenderMultiColumnBlock::renderName() const -{ - if (isFloating()) - return "RenderMultiColumnBlock (floating)"; - if (isOutOfFlowPositioned()) - return "RenderMultiColumnBlock (positioned)"; - if (isAnonymousBlock()) - return "RenderMultiColumnBlock (anonymous)"; - // FIXME: Temporary hack while the new generated content system is being implemented. - if (isPseudoElement()) - return "RenderMultiColumnBlock (generated)"; - if (isAnonymous()) - return "RenderMultiColumnBlock (generated)"; - if (isRelPositioned()) - return "RenderMultiColumnBlock (relative positioned)"; - return "RenderMultiColumnBlock"; -} - -} diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnBlock.h b/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnBlock.h deleted file mode 100644 index ac92d2f9ff9..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnBlock.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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 "core/rendering/RenderBlockFlow.h" - -namespace WebCore { - -class RenderMultiColumnFlowThread; - -class RenderMultiColumnBlock FINAL : public RenderBlockFlow { -public: - RenderMultiColumnBlock(Element*); - - LayoutUnit columnHeightAvailable() const { return m_columnHeightAvailable; } - - LayoutUnit columnWidth() const { return m_columnWidth; } - unsigned columnCount() const { return m_columnCount; } - - RenderMultiColumnFlowThread* flowThread() const { return m_flowThread; } - - bool requiresBalancing() const { return !m_columnHeightAvailable || style()->columnFill() == ColumnFillBalance; } - -private: - virtual bool isRenderMultiColumnBlock() const { return true; } - - virtual const char* renderName() const; - - virtual RenderObject* layoutSpecialExcludedChild(bool relayoutChildren, SubtreeLayoutScope&) OVERRIDE; - - virtual void styleDidChange(StyleDifference, const RenderStyle*) OVERRIDE; - - virtual bool updateLogicalWidthAndColumnWidth() OVERRIDE; - virtual void checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight) OVERRIDE; - virtual bool relayoutForPagination(bool hasSpecifiedPageLogicalHeight, LayoutUnit pageLogicalHeight, LayoutStateMaintainer&) OVERRIDE; - - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - - virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0) OVERRIDE; - - void computeColumnCountAndWidth(); - - void ensureColumnSets(); - - RenderMultiColumnFlowThread* m_flowThread; - 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. - LayoutUnit m_columnHeightAvailable; // Total height available to columns, or 0 if auto. - bool m_inBalancingPass; // Set when relayouting for column balancing. -}; - -DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderMultiColumnBlock, isRenderMultiColumnBlock()); - -} // namespace WebCore - -#endif // RenderMultiColumnBlock_h - diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnFlowThread.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnFlowThread.cpp index 1a2fc6f74b2..9b50901bcba 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnFlowThread.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnFlowThread.cpp @@ -26,12 +26,15 @@ #include "config.h" #include "core/rendering/RenderMultiColumnFlowThread.h" -#include "core/rendering/RenderMultiColumnBlock.h" #include "core/rendering/RenderMultiColumnSet.h" namespace WebCore { RenderMultiColumnFlowThread::RenderMultiColumnFlowThread() + : m_columnCount(1) + , m_columnHeightAvailable(0) + , m_inBalancingPass(false) + , m_needsColumnHeightsRecalculation(false) { setFlowThreadState(InsideInFlowThread); } @@ -40,72 +43,249 @@ RenderMultiColumnFlowThread::~RenderMultiColumnFlowThread() { } -RenderMultiColumnFlowThread* RenderMultiColumnFlowThread::createAnonymous(Document* document) +RenderMultiColumnFlowThread* RenderMultiColumnFlowThread::createAnonymous(Document& document, RenderStyle* parentStyle) { RenderMultiColumnFlowThread* renderer = new RenderMultiColumnFlowThread(); - renderer->setDocumentForAnonymous(document); + renderer->setDocumentForAnonymous(&document); + renderer->setStyle(RenderStyle::createAnonymousStyleWithDisplay(parentStyle, BLOCK)); return renderer; } -const char* RenderMultiColumnFlowThread::renderName() const +RenderMultiColumnSet* RenderMultiColumnFlowThread::firstMultiColumnSet() const { - return "RenderMultiColumnFlowThread"; + for (RenderObject* sibling = nextSibling(); sibling; sibling = sibling->nextSibling()) { + if (sibling->isRenderMultiColumnSet()) + return toRenderMultiColumnSet(sibling); + } + return 0; } -void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const +RenderMultiColumnSet* RenderMultiColumnFlowThread::lastMultiColumnSet() const { - // We simply remain at our intrinsic height. - computedValues.m_extent = logicalHeight; - computedValues.m_position = logicalTop; + for (RenderObject* sibling = multiColumnBlockFlow()->lastChild(); sibling; sibling = sibling->previousSibling()) { + if (sibling->isRenderMultiColumnSet()) + return toRenderMultiColumnSet(sibling); + } + return 0; } -LayoutUnit RenderMultiColumnFlowThread::initialLogicalWidth() const -{ - RenderMultiColumnBlock* parentBlock = toRenderMultiColumnBlock(parent()); - return parentBlock->columnWidth(); -} - -void RenderMultiColumnFlowThread::autoGenerateRegionsToBlockOffset(LayoutUnit /*offset*/) -{ - // This function ensures we have the correct column set information at all times. - // For a simple multi-column layout in continuous media, only one column set child is required. - // Once a column is nested inside an enclosing pagination context, the number of column sets - // required becomes 2n-1, where n is the total number of nested pagination contexts. For example: - // - // Column layout with no enclosing pagination model = 2 * 1 - 1 = 1 column set. - // Columns inside pages = 2 * 2 - 1 = 3 column sets (bottom of first page, all the subsequent pages, then the last page). - // Columns inside columns inside pages = 2 * 3 - 1 = 5 column sets. - // - // In addition, column spans will force a column set to "split" into before/after sets around the spanning element. - // - // Finally, we will need to deal with columns inside regions. If regions have variable widths, then there will need - // to be unique column sets created inside any region whose width is different from its surrounding regions. This is - // actually pretty similar to the spanning case, in that we break up the column sets whenever the width varies. - // - // FIXME: For now just make one column set. This matches the old multi-column code. - // Right now our goal is just feature parity with the old multi-column code so that we can switch over to the - // new code as soon as possible. - RenderMultiColumnSet* firstSet = toRenderMultiColumnSet(firstRegion()); - if (firstSet) +void RenderMultiColumnFlowThread::addChild(RenderObject* newChild, RenderObject* beforeChild) +{ + RenderBlockFlow::addChild(newChild, beforeChild); + if (firstMultiColumnSet()) return; + // For now we only create one column set. It's created as soon as the multicol container gets + // any content at all. + RenderMultiColumnSet* newSet = RenderMultiColumnSet::createAnonymous(this, multiColumnBlockFlow()->style()); + + // Need to skip RenderBlockFlow's implementation of addChild(), or we'd get redirected right + // back here. + multiColumnBlockFlow()->RenderBlock::addChild(newSet); + invalidateRegions(); +} - RenderMultiColumnBlock* parentBlock = toRenderMultiColumnBlock(parent()); - firstSet = RenderMultiColumnSet::createAnonymous(this); - firstSet->setStyle(RenderStyle::createAnonymousStyleWithDisplay(parentBlock->style(), BLOCK)); - parentBlock->RenderBlock::addChild(firstSet); +void RenderMultiColumnFlowThread::populate() +{ + RenderBlockFlow* multicolContainer = multiColumnBlockFlow(); + ASSERT(!nextSibling()); + // Reparent children preceding the flow thread into the flow thread. It's multicol content + // now. At this point there's obviously nothing after the flow thread, but renderers (column + // sets and spanners) will be inserted there as we insert elements into the flow thread. + multicolContainer->moveChildrenTo(this, multicolContainer->firstChild(), this, true); +} + +void RenderMultiColumnFlowThread::evacuateAndDestroy() +{ + RenderBlockFlow* multicolContainer = multiColumnBlockFlow(); + + // Remove all sets. + while (RenderMultiColumnSet* columnSet = firstMultiColumnSet()) + columnSet->destroy(); - // Even though we aren't placed yet, we can go ahead and set up our size. At this point we're - // typically in the middle of laying out the thread, attempting to paginate, and we need to do - // some rudimentary "layout" of the set now, so that pagination will work. - firstSet->prepareForLayout(); + ASSERT(!previousSibling()); + ASSERT(!nextSibling()); + // Finally we can promote all flow thread's children. Before we move them to the flow thread's + // container, we need to unregister the flow thread, so that they aren't just re-added again to + // the flow thread that we're trying to empty. + multicolContainer->resetMultiColumnFlowThread(); + moveAllChildrenTo(multicolContainer, true); + + // FIXME: it's scary that neither destroy() nor the move*Children* methods take care of this, + // and instead leave you with dangling root line box pointers. But since this is how it is done + // in other parts of the code that deal with reparenting renderers, let's do the cleanup on our + // own here as well. + deleteLineBoxTree(); + + destroy(); +} + +LayoutSize RenderMultiColumnFlowThread::columnOffset(const LayoutPoint& point) const +{ + if (!hasValidRegionInfo()) + return LayoutSize(0, 0); + + LayoutPoint flowThreadPoint(point); + flipForWritingMode(flowThreadPoint); + LayoutUnit blockOffset = isHorizontalWritingMode() ? flowThreadPoint.y() : flowThreadPoint.x(); + RenderRegion* renderRegion = regionAtBlockOffset(blockOffset); + if (!renderRegion) + return LayoutSize(0, 0); + return toRenderMultiColumnSet(renderRegion)->flowThreadTranslationAtOffset(blockOffset); +} + +bool RenderMultiColumnFlowThread::needsNewWidth() const +{ + LayoutUnit newWidth; + unsigned dummyColumnCount; // We only care if used column-width changes. + calculateColumnCountAndWidth(newWidth, dummyColumnCount); + return newWidth != logicalWidth(); +} + +void RenderMultiColumnFlowThread::layoutColumns(bool relayoutChildren, SubtreeLayoutScope& layoutScope) +{ + if (relayoutChildren) + layoutScope.setChildNeedsLayout(this); + + if (!needsLayout()) { + // Just before the multicol container (our parent RenderBlockFlow) finishes laying out, it + // will call recalculateColumnHeights() on us unconditionally, but we only want that method + // to do any work if we actually laid out the flow thread. Otherwise, the balancing + // machinery would kick in needlessly, and trigger additional layout passes. Furthermore, we + // actually depend on a proper flowthread layout pass in order to do balancing, since it's + // flowthread layout that sets up content runs. + m_needsColumnHeightsRecalculation = false; + return; + } + + for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet()) { + if (!m_inBalancingPass) { + // This is the initial layout pass. We need to reset the column height, because contents + // typically have changed. + columnSet->resetColumnHeight(); + } + } + + invalidateRegions(); + m_needsColumnHeightsRecalculation = requiresBalancing(); + layout(); +} + +bool RenderMultiColumnFlowThread::recalculateColumnHeights() +{ + // All column sets that needed layout have now been laid out, so we can finally validate them. validateRegions(); + + if (!m_needsColumnHeightsRecalculation) + return false; + + // Column heights may change here because of balancing. We may have to do multiple layout + // passes, depending on how the contents is fitted to the changed column heights. In most + // cases, laying out again twice or even just once will suffice. Sometimes we need more + // passes than that, though, but the number of retries should not exceed the number of + // columns, unless we have a bug. + bool needsRelayout = false; + for (RenderMultiColumnSet* multicolSet = firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) { + needsRelayout |= multicolSet->recalculateColumnHeight(m_inBalancingPass ? RenderMultiColumnSet::StretchBySpaceShortage : RenderMultiColumnSet::GuessFromFlowThreadPortion); + if (needsRelayout) { + // Once a column set gets a new column height, that column set and all successive column + // sets need to be laid out over again, since their logical top will be affected by + // this, and therefore their column heights may change as well, at least if the multicol + // height is constrained. + multicolSet->setChildNeedsLayout(MarkOnlyThis); + } + } + + if (needsRelayout) + setChildNeedsLayout(MarkOnlyThis); + + m_inBalancingPass = needsRelayout; + return needsRelayout; +} + +void RenderMultiColumnFlowThread::calculateColumnCountAndWidth(LayoutUnit& width, unsigned& count) const +{ + RenderBlock* columnBlock = multiColumnBlockFlow(); + const RenderStyle* columnStyle = columnBlock->style(); + LayoutUnit availableWidth = columnBlock->contentLogicalWidth(); + LayoutUnit columnGap = columnBlock->columnGap(); + LayoutUnit computedColumnWidth = max<LayoutUnit>(1, LayoutUnit(columnStyle->columnWidth())); + unsigned computedColumnCount = max<int>(1, columnStyle->columnCount()); + + ASSERT(!columnStyle->hasAutoColumnCount() || !columnStyle->hasAutoColumnWidth()); + if (columnStyle->hasAutoColumnWidth() && !columnStyle->hasAutoColumnCount()) { + count = computedColumnCount; + width = std::max<LayoutUnit>(0, (availableWidth - ((count - 1) * columnGap)) / count); + } else if (!columnStyle->hasAutoColumnWidth() && columnStyle->hasAutoColumnCount()) { + count = std::max<LayoutUnit>(1, (availableWidth + columnGap) / (computedColumnWidth + columnGap)); + width = ((availableWidth + columnGap) / count) - columnGap; + } else { + count = std::max<LayoutUnit>(std::min<LayoutUnit>(computedColumnCount, (availableWidth + columnGap) / (computedColumnWidth + columnGap)), 1); + width = ((availableWidth + columnGap) / count) - columnGap; + } +} + +const char* RenderMultiColumnFlowThread::renderName() const +{ + return "RenderMultiColumnFlowThread"; +} + +void RenderMultiColumnFlowThread::addRegionToThread(RenderRegion* renderRegion) +{ + RenderMultiColumnSet* columnSet = toRenderMultiColumnSet(renderRegion); + if (RenderMultiColumnSet* nextSet = columnSet->nextSiblingMultiColumnSet()) { + RenderRegionList::iterator it = m_regionList.find(nextSet); + ASSERT(it != m_regionList.end()); + m_regionList.insertBefore(it, columnSet); + } else { + m_regionList.add(columnSet); + } + renderRegion->setIsValid(true); +} + +void RenderMultiColumnFlowThread::willBeRemovedFromTree() +{ + // Detach all column sets from the flow thread. Cannot destroy them at this point, since they + // are siblings of this object, and there may be pointers to this object's sibling somewhere + // further up on the call stack. + for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet()) + columnSet->detachRegion(); + multiColumnBlockFlow()->resetMultiColumnFlowThread(); + RenderFlowThread::willBeRemovedFromTree(); +} + +void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const +{ + // We simply remain at our intrinsic height. + computedValues.m_extent = logicalHeight; + computedValues.m_position = logicalTop; +} + +void RenderMultiColumnFlowThread::updateLogicalWidth() +{ + LayoutUnit columnWidth; + calculateColumnCountAndWidth(columnWidth, m_columnCount); + setLogicalWidth(columnWidth); +} + +void RenderMultiColumnFlowThread::layout() +{ + RenderFlowThread::layout(); + if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) + lastSet->expandToEncompassFlowThreadContentsIfNeeded(); } void RenderMultiColumnFlowThread::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage) { + // Only positive values are interesting (and allowed) here. Zero space shortage may be reported + // when we're at the top of a column and the element has zero height. Ignore this, and also + // ignore any negative values, which may occur when we set an early break in order to honor + // widows in the next column. + if (spaceShortage <= 0) + return; + if (RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(regionAtBlockOffset(offset))) multicolSet->recordSpaceShortage(spaceShortage); } @@ -116,4 +296,28 @@ void RenderMultiColumnFlowThread::updateMinimumPageHeight(LayoutUnit offset, Lay multicolSet->updateMinimumColumnHeight(minHeight); } +RenderRegion* RenderMultiColumnFlowThread::regionAtBlockOffset(LayoutUnit /*offset*/) const +{ + // For now there's only one column set, so this is easy: + return firstMultiColumnSet(); +} + +bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, RenderObject* /*breakChild*/, bool /*isBefore*/, LayoutUnit* offsetBreakAdjustment) +{ + if (RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(regionAtBlockOffset(offset))) { + multicolSet->addContentRun(offset); + if (offsetBreakAdjustment) + *offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRemainingLogicalHeightForOffset(offset, IncludePageBoundary) : LayoutUnit(); + return true; + } + return false; +} + +bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const +{ + if (RenderMultiColumnSet* columnSet = lastMultiColumnSet()) + return columnSet->pageLogicalHeight(); + return false; +} + } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnFlowThread.h b/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnFlowThread.h index ace5c43cbfc..ff5784835b1 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnFlowThread.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnFlowThread.h @@ -31,21 +31,118 @@ namespace WebCore { +class RenderMultiColumnSet; + +// Flow thread implementation for CSS multicol. This will be inserted as an anonymous child block of +// the actual multicol container (i.e. the RenderBlockFlow whose style computes to non-auto +// column-count and/or column-width). RenderMultiColumnFlowThread is the heart of the multicol +// implementation, and there is only one instance per multicol container. Child content of the +// multicol container is parented into the flow thread at the time of renderer insertion. +// +// Apart from this flow thread child, the multicol container will also have RenderMultiColumnSet +// "region" children, which are used to position the columns visually. The flow thread is in charge +// of layout, and, after having calculated the column width, it lays out content as if everything +// were in one tall single column, except that there will typically be some amount of blank space +// (also known as pagination struts) at the offsets where the actual column boundaries are. This +// way, content that needs to be preceded by a break will appear at the top of the next +// column. Content needs to be preceded by a break when there's a forced break or when the content +// is unbreakable and cannot fully fit in the same column as the preceding piece of +// content. Although a RenderMultiColumnFlowThread is laid out, it does not take up any space in its +// container. It's the RenderMultiColumnSet objects that take up the necessary amount of space, and +// make sure that the columns are painted and hit-tested correctly. +// +// The width of the flow thread is the same as the column width. The width of a column set is the +// same as the content box width of the multicol container; in other words exactly enough to hold +// the number of columns to be used, stacked horizontally, plus column gaps between them. +// +// Since it's the first child of the multicol container, the flow thread is laid out first, albeit +// in a slightly special way, since it's not to take up any space in its ancestors. Afterwards, the +// column sets are laid out. They get their height from the columns that they hold. In single +// column-row constrained height non-balancing cases this will simply be the same as the content +// height of the multicol container itself. In most other cases we'll have to calculate optimal +// column heights ourselves, though. This process is referred to as column balancing, and then we +// infer the column set height from the flow thread's height. +// +// More on column balancing: the columns' height is unknown in the first layout pass when +// balancing. This means that we cannot insert any implicit (soft / unforced) breaks (and pagination +// struts) when laying out the contents of the flow thread. We'll just lay out everything in tall +// single strip. After the initial flow thread layout pass we can determine a tentative / minimal / +// initial column height. This is calculated by simply dividing the flow thread's height by the +// number of specified columns. In the layout pass that follows, we can insert breaks (and +// pagination struts) at column boundaries, since we now have a column height. It may very easily +// turn out that the calculated height wasn't enough, though. We'll notice this at end of layout. If +// we end up with too many columns (i.e. columns overflowing the multicol container), it wasn't +// enough. In this case we need to increase the column heights. We'll increase them by the lowest +// amount of space that could possibly affect where the breaks occur (see +// RenderMultiColumnSet::recordSpaceShortage()). We'll relayout (to find new break points and the +// new lowest amount of space increase that could affect where they occur, in case we need another +// round) until we've reached an acceptable height (where everything fits perfectly in the number of +// columns that we have specified). The rule of thumb is that we shouldn't have to perform more of +// such iterations than the number of columns that we have. +// +// For each layout iteration done for column balancing, the flow thread will need a deep layout if +// column heights changed in the previous pass, since column height changes may affect break points +// and pagination struts anywhere in the tree, and currently no way exists to do this in a more +// optimized manner. class RenderMultiColumnFlowThread FINAL : public RenderFlowThread { public: - ~RenderMultiColumnFlowThread(); + virtual ~RenderMultiColumnFlowThread(); + + static RenderMultiColumnFlowThread* createAnonymous(Document&, RenderStyle* parentStyle); + + virtual bool isRenderMultiColumnFlowThread() const OVERRIDE FINAL { return true; } + + RenderBlockFlow* multiColumnBlockFlow() const { return toRenderBlockFlow(parent()); } + + RenderMultiColumnSet* firstMultiColumnSet() const; + RenderMultiColumnSet* lastMultiColumnSet() const; + + virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0) OVERRIDE; + + // Populate the flow thread with what's currently its siblings. Called when a regular block + // becomes a multicol container. + void populate(); - static RenderMultiColumnFlowThread* createAnonymous(Document*); + // Empty the flow thread by moving everything to the parent. Remove all multicol specific + // renderers. Then destroy the flow thread. Called when a multicol container becomes a regular + // block. + void evacuateAndDestroy(); + + unsigned columnCount() const { return m_columnCount; } + LayoutUnit columnHeightAvailable() const { return m_columnHeightAvailable; } + void setColumnHeightAvailable(LayoutUnit available) { m_columnHeightAvailable = available; } + bool requiresBalancing() const { return !columnHeightAvailable() || multiColumnBlockFlow()->style()->columnFill() == ColumnFillBalance; } + + virtual LayoutSize columnOffset(const LayoutPoint&) const OVERRIDE FINAL; + + // Do we need to set a new width and lay out? + bool needsNewWidth() const; + + void layoutColumns(bool relayoutChildren, SubtreeLayoutScope&); + + bool recalculateColumnHeights(); private: RenderMultiColumnFlowThread(); + void calculateColumnCountAndWidth(LayoutUnit& width, unsigned& count) const; + virtual const char* renderName() const OVERRIDE; + virtual void addRegionToThread(RenderRegion*) OVERRIDE; + virtual void willBeRemovedFromTree() OVERRIDE; virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE; - virtual void autoGenerateRegionsToBlockOffset(LayoutUnit) OVERRIDE; - virtual LayoutUnit initialLogicalWidth() const OVERRIDE; + virtual void updateLogicalWidth() OVERRIDE FINAL; + virtual void layout() OVERRIDE FINAL; virtual void setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage) OVERRIDE; virtual void updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight) OVERRIDE; + virtual RenderRegion* regionAtBlockOffset(LayoutUnit) const OVERRIDE; + virtual bool addForcedRegionBreak(LayoutUnit, RenderObject* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment = 0) OVERRIDE; + virtual bool isPageLogicalHeightKnown() const OVERRIDE; + + unsigned m_columnCount; // The used value of column-count + LayoutUnit m_columnHeightAvailable; // Total height available to columns, or 0 if auto. + bool m_inBalancingPass; // Set when relayouting for column balancing. + bool m_needsColumnHeightsRecalculation; // Set when we need to recalculate the column set heights after layout. }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnSet.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnSet.cpp index 449073752ae..eee9aee2b43 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnSet.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnSet.cpp @@ -28,7 +28,6 @@ #include "core/rendering/PaintInfo.h" #include "core/rendering/RenderLayer.h" -#include "core/rendering/RenderMultiColumnBlock.h" #include "core/rendering/RenderMultiColumnFlowThread.h" using namespace std; @@ -36,91 +35,202 @@ using namespace std; namespace WebCore { RenderMultiColumnSet::RenderMultiColumnSet(RenderFlowThread* flowThread) - : RenderRegionSet(0, flowThread) - , m_computedColumnCount(1) - , m_computedColumnWidth(0) - , m_computedColumnHeight(0) - , m_maxColumnHeight(LayoutUnit::max()) - , m_minSpaceShortage(LayoutUnit::max()) + : RenderRegion(0, flowThread) + , m_columnHeight(0) + , m_maxColumnHeight(RenderFlowThread::maxLogicalHeight()) + , m_minSpaceShortage(RenderFlowThread::maxLogicalHeight()) , m_minimumColumnHeight(0) - , m_forcedBreaksCount(0) - , m_maximumDistanceBetweenForcedBreaks(0) - , m_forcedBreakOffset(0) { } -RenderMultiColumnSet* RenderMultiColumnSet::createAnonymous(RenderFlowThread* flowThread) +RenderMultiColumnSet* RenderMultiColumnSet::createAnonymous(RenderFlowThread* flowThread, RenderStyle* parentStyle) { Document& document = flowThread->document(); RenderMultiColumnSet* renderer = new RenderMultiColumnSet(flowThread); renderer->setDocumentForAnonymous(&document); + renderer->setStyle(RenderStyle::createAnonymousStyleWithDisplay(parentStyle, BLOCK)); return renderer; } -LayoutUnit RenderMultiColumnSet::heightAdjustedForSetOffset(LayoutUnit height) const +RenderMultiColumnSet* RenderMultiColumnSet::nextSiblingMultiColumnSet() const +{ + for (RenderObject* sibling = nextSibling(); sibling; sibling = sibling->nextSibling()) { + if (sibling->isRenderMultiColumnSet()) + return toRenderMultiColumnSet(sibling); + } + return 0; +} + +RenderMultiColumnSet* RenderMultiColumnSet::previousSiblingMultiColumnSet() const +{ + for (RenderObject* sibling = previousSibling(); sibling; sibling = sibling->previousSibling()) { + if (sibling->isRenderMultiColumnSet()) + return toRenderMultiColumnSet(sibling); + } + return 0; +} + +LayoutSize RenderMultiColumnSet::flowThreadTranslationAtOffset(LayoutUnit blockOffset) const { - RenderMultiColumnBlock* multicolBlock = toRenderMultiColumnBlock(parent()); - LayoutUnit contentLogicalTop = logicalTop() - multicolBlock->borderBefore() - multicolBlock->paddingBefore(); + unsigned columnIndex = columnIndexAtOffset(blockOffset); + LayoutRect portionRect(flowThreadPortionRectAt(columnIndex)); + flipForWritingMode(portionRect); + LayoutRect columnRect(columnRectAt(columnIndex)); + flipForWritingMode(columnRect); + return contentBoxRect().location() + columnRect.location() - portionRect.location(); +} - height -= contentLogicalTop; +LayoutUnit RenderMultiColumnSet::heightAdjustedForSetOffset(LayoutUnit height) const +{ + // Adjust for the top offset within the content box of the multicol container (containing + // block), unless this is the first set. We know that the top offset for the first set will be + // zero, but if the multicol container has non-zero top border or padding, the set's top offset + // (initially being 0 and relative to the border box) will be negative until it has been laid + // out. Had we used this bogus offset, we would calculate the wrong height, and risk performing + // a wasted layout iteration. Of course all other sets (if any) have this problem in the first + // layout pass too, but there's really nothing we can do there until the flow thread has been + // laid out anyway. + if (previousSiblingMultiColumnSet()) { + RenderBlockFlow* multicolBlock = multiColumnBlockFlow(); + LayoutUnit contentLogicalTop = logicalTop() - multicolBlock->borderAndPaddingBefore(); + height -= contentLogicalTop; + } return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would probably cause an infinite amount of columns to be created. } LayoutUnit RenderMultiColumnSet::pageLogicalTopForOffset(LayoutUnit offset) const { - LayoutUnit portionLogicalTop = (isHorizontalWritingMode() ? flowThreadPortionRect().y() : flowThreadPortionRect().x()); unsigned columnIndex = columnIndexAtOffset(offset, AssumeNewColumns); - return portionLogicalTop + columnIndex * computedColumnHeight(); + return logicalTopInFlowThread() + columnIndex * pageLogicalHeight(); } void RenderMultiColumnSet::setAndConstrainColumnHeight(LayoutUnit newHeight) { - m_computedColumnHeight = newHeight; - if (m_computedColumnHeight > m_maxColumnHeight) - m_computedColumnHeight = m_maxColumnHeight; + m_columnHeight = newHeight; + if (m_columnHeight > m_maxColumnHeight) + m_columnHeight = m_maxColumnHeight; // FIXME: the height may also be affected by the enclosing pagination context, if any. } -bool RenderMultiColumnSet::calculateBalancedHeight(bool initial) +unsigned RenderMultiColumnSet::findRunWithTallestColumns() const +{ + unsigned indexWithLargestHeight = 0; + LayoutUnit largestHeight; + LayoutUnit previousOffset = logicalTopInFlowThread(); + size_t runCount = m_contentRuns.size(); + ASSERT(runCount); + for (size_t i = 0; i < runCount; i++) { + const ContentRun& run = m_contentRuns[i]; + LayoutUnit height = run.columnLogicalHeight(previousOffset); + if (largestHeight < height) { + largestHeight = height; + indexWithLargestHeight = i; + } + previousOffset = run.breakOffset(); + } + return indexWithLargestHeight; +} + +void RenderMultiColumnSet::distributeImplicitBreaks() +{ +#ifndef NDEBUG + // There should be no implicit breaks assumed at this point. + for (unsigned i = 0; i < m_contentRuns.size(); i++) + ASSERT(!m_contentRuns[i].assumedImplicitBreaks()); +#endif // NDEBUG + + // Insert a final content run to encompass all content. This will include overflow if this is + // the last set. + addContentRun(logicalBottomInFlowThread()); + unsigned columnCount = m_contentRuns.size(); + + // If there is room for more breaks (to reach the used value of column-count), imagine that we + // insert implicit breaks at suitable locations. At any given time, the content run with the + // currently tallest columns will get another implicit break "inserted", which will increase its + // column count by one and shrink its columns' height. Repeat until we have the desired total + // number of breaks. The largest column height among the runs will then be the initial column + // height for the balancer to use. + while (columnCount < usedColumnCount()) { + unsigned index = findRunWithTallestColumns(); + m_contentRuns[index].assumeAnotherImplicitBreak(); + columnCount++; + } +} + +LayoutUnit RenderMultiColumnSet::calculateColumnHeight(BalancedHeightCalculation calculationMode) const { - ASSERT(toRenderMultiColumnBlock(parent())->requiresBalancing()); - LayoutUnit oldColumnHeight = m_computedColumnHeight; - LayoutUnit currentMinSpaceShortage = m_minSpaceShortage; - m_minSpaceShortage = LayoutUnit::max(); - - if (initial) { - // Start with the lowest imaginable column height. - LayoutUnit logicalHeightGuess = ceilf(float(flowThread()->logicalHeight()) / float(m_computedColumnCount)); - logicalHeightGuess = max(logicalHeightGuess, m_minimumColumnHeight); - setAndConstrainColumnHeight(logicalHeightGuess); - - // The multicol container now typically needs at least one more layout pass with a new - // column height, but if height was specified, we only need to do this if we found that we - // might need less space than that. On the other hand, if we determined that the columns - // need to be as tall as the specified height of the container, we have already laid it out - // correctly, and there's no need for another pass. - return m_computedColumnHeight != oldColumnHeight; + if (calculationMode == GuessFromFlowThreadPortion) { + // Initial balancing. Start with the lowest imaginable column height. We use the tallest + // content run (after having "inserted" implicit breaks), and find its start offset (by + // looking at the previous run's end offset, or, if there's no previous run, the set's start + // offset in the flow thread). + unsigned index = findRunWithTallestColumns(); + LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset() : logicalTopInFlowThread(); + return std::max<LayoutUnit>(m_contentRuns[index].columnLogicalHeight(startOffset), m_minimumColumnHeight); } - if (columnCount() <= computedColumnCount()) { + if (actualColumnCount() <= usedColumnCount()) { // With the current column height, the content fits without creating overflowing columns. We're done. - return false; + return m_columnHeight; + } + + if (m_contentRuns.size() >= usedColumnCount()) { + // Too many forced breaks to allow any implicit breaks. Initial balancing should already + // have set a good height. There's nothing more we should do. + return m_columnHeight; } // If the initial guessed column height wasn't enough, stretch it now. Stretch by the lowest // amount of space shortage found during layout. - ASSERT(currentMinSpaceShortage != LayoutUnit::max()); // If this can actually happen, we probably have a bug. - if (currentMinSpaceShortage == LayoutUnit::max()) - return false; // So bail out rather than looping infinitely. + ASSERT(m_minSpaceShortage > 0); // We should never _shrink_ the height! + ASSERT(m_minSpaceShortage != RenderFlowThread::maxLogicalHeight()); // If this happens, we probably have a bug. + if (m_minSpaceShortage == RenderFlowThread::maxLogicalHeight()) + return m_columnHeight; // So bail out rather than looping infinitely. + + return m_columnHeight + m_minSpaceShortage; +} + +void RenderMultiColumnSet::addContentRun(LayoutUnit endOffsetFromFirstPage) +{ + if (!multiColumnFlowThread()->requiresBalancing()) + return; + if (!m_contentRuns.isEmpty() && endOffsetFromFirstPage <= m_contentRuns.last().breakOffset()) + return; + // Append another item as long as we haven't exceeded used column count. What ends up in the + // overflow area shouldn't affect column balancing. + if (m_contentRuns.size() < usedColumnCount()) + m_contentRuns.append(ContentRun(endOffsetFromFirstPage)); +} + +bool RenderMultiColumnSet::recalculateColumnHeight(BalancedHeightCalculation calculationMode) +{ + ASSERT(multiColumnFlowThread()->requiresBalancing()); + + LayoutUnit oldColumnHeight = m_columnHeight; + if (calculationMode == GuessFromFlowThreadPortion) { + // Post-process the content runs and find out where the implicit breaks will occur. + distributeImplicitBreaks(); + } + LayoutUnit newColumnHeight = calculateColumnHeight(calculationMode); + setAndConstrainColumnHeight(newColumnHeight); + + // After having calculated an initial column height, the multicol container typically needs at + // least one more layout pass with a new column height, but if a height was specified, we only + // need to do this if we think that we need less space than specified. Conversely, if we + // determined that the columns need to be as tall as the specified height of the container, we + // have already laid it out correctly, and there's no need for another pass. - setAndConstrainColumnHeight(m_computedColumnHeight + currentMinSpaceShortage); + // We can get rid of the content runs now, if we haven't already done so. They are only needed + // to calculate the initial balanced column height. In fact, we have to get rid of them before + // the next layout pass, since each pass will rebuild this. + m_contentRuns.clear(); - // If we reach the maximum column height (typically set by the height or max-height property), - // we may not be allowed to stretch further. Return true only if stretching - // succeeded. Otherwise, we're done. - ASSERT(m_computedColumnHeight >= oldColumnHeight); // We shouldn't be able to shrink the height! - return m_computedColumnHeight > oldColumnHeight; + if (m_columnHeight == oldColumnHeight) + return false; // No change. We're done. + + m_minSpaceShortage = RenderFlowThread::maxLogicalHeight(); + return true; // Need another pass. } void RenderMultiColumnSet::recordSpaceShortage(LayoutUnit spaceShortage) @@ -135,94 +245,95 @@ void RenderMultiColumnSet::recordSpaceShortage(LayoutUnit spaceShortage) m_minSpaceShortage = spaceShortage; } -void RenderMultiColumnSet::updateLogicalWidth() +void RenderMultiColumnSet::resetColumnHeight() { - RenderMultiColumnBlock* parentBlock = toRenderMultiColumnBlock(parent()); - setComputedColumnWidthAndCount(parentBlock->columnWidth(), parentBlock->columnCount()); // FIXME: This will eventually vary if we are contained inside regions. + // Nuke previously stored minimum column height. Contents may have changed for all we know. + m_minimumColumnHeight = 0; - // FIXME: When we add regions support, we'll start it off at the width of the multi-column - // block in that particular region. - setLogicalWidth(parentBox()->contentLogicalWidth()); + m_maxColumnHeight = calculateMaxColumnHeight(); - // If we overflow, increase our logical width. - unsigned colCount = columnCount(); - LayoutUnit colGap = columnGap(); - LayoutUnit minimumContentLogicalWidth = colCount * computedColumnWidth() + (colCount - 1) * colGap; - LayoutUnit currentContentLogicalWidth = contentLogicalWidth(); - LayoutUnit delta = max(LayoutUnit(), minimumContentLogicalWidth - currentContentLogicalWidth); - if (!delta) - return; + LayoutUnit oldColumnHeight = pageLogicalHeight(); - // Increase our logical width by the delta. - setLogicalWidth(logicalWidth() + delta); -} + if (multiColumnFlowThread()->requiresBalancing()) + m_columnHeight = 0; + else + setAndConstrainColumnHeight(heightAdjustedForSetOffset(multiColumnFlowThread()->columnHeightAvailable())); -void RenderMultiColumnSet::prepareForLayout() -{ - RenderMultiColumnBlock* multicolBlock = toRenderMultiColumnBlock(parent()); - RenderStyle* multicolStyle = multicolBlock->style(); + if (pageLogicalHeight() != oldColumnHeight) + setChildNeedsLayout(MarkOnlyThis); - // Set box logical top. - ASSERT(!previousSiblingBox() || !previousSiblingBox()->isRenderMultiColumnSet()); // FIXME: multiple set not implemented; need to examine previous set to calculate the correct logical top. - setLogicalTop(multicolBlock->borderBefore() + multicolBlock->paddingBefore()); - - // Set box width. - updateLogicalWidth(); - - if (multicolBlock->requiresBalancing()) { - // Set maximum column height. We will not stretch beyond this. - m_maxColumnHeight = LayoutUnit::max(); - if (!multicolStyle->logicalHeight().isAuto()) - m_maxColumnHeight = multicolBlock->computeContentLogicalHeight(multicolStyle->logicalHeight(), -1); - if (!multicolStyle->logicalMaxHeight().isUndefined()) { - LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight(multicolStyle->logicalMaxHeight(), -1); - if (m_maxColumnHeight > logicalMaxHeight) - m_maxColumnHeight = logicalMaxHeight; - } - m_maxColumnHeight = heightAdjustedForSetOffset(m_maxColumnHeight); - m_computedColumnHeight = 0; // Restart balancing. - } else { - setAndConstrainColumnHeight(heightAdjustedForSetOffset(multicolBlock->columnHeightAvailable())); - } + // Content runs are only needed in the initial layout pass, in order to find an initial column + // height, and should have been deleted afterwards. We're about to rebuild the content runs, so + // the list needs to be empty. + ASSERT(m_contentRuns.isEmpty()); +} - // Nuke previously stored minimum column height. Contents may have changed for all we know. - m_minimumColumnHeight = 0; +void RenderMultiColumnSet::expandToEncompassFlowThreadContentsIfNeeded() +{ + ASSERT(multiColumnFlowThread()->lastMultiColumnSet() == this); + LayoutRect rect(flowThreadPortionRect()); + + // Get the offset within the flow thread in its block progression direction. Then get the + // flow thread's remaining logical height including its overflow and expand our rect + // to encompass that remaining height and overflow. The idea is that we will generate + // additional columns and pages to hold that overflow, since people do write bad + // content like <body style="height:0px"> in multi-column layouts. + bool isHorizontal = flowThread()->isHorizontalWritingMode(); + LayoutUnit logicalTopOffset = isHorizontal ? rect.y() : rect.x(); + LayoutRect layoutRect = flowThread()->layoutOverflowRect(); + LayoutUnit logicalHeightWithOverflow = (isHorizontal ? layoutRect.maxY() : layoutRect.maxX()) - logicalTopOffset; + setFlowThreadPortionRect(LayoutRect(rect.x(), rect.y(), isHorizontal ? rect.width() : logicalHeightWithOverflow, isHorizontal ? logicalHeightWithOverflow : rect.height())); } void RenderMultiColumnSet::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const { - computedValues.m_extent = m_computedColumnHeight; + computedValues.m_extent = m_columnHeight; computedValues.m_position = logicalTop; } +LayoutUnit RenderMultiColumnSet::calculateMaxColumnHeight() const +{ + RenderBlockFlow* multicolBlock = multiColumnBlockFlow(); + RenderStyle* multicolStyle = multicolBlock->style(); + LayoutUnit availableHeight = multiColumnFlowThread()->columnHeightAvailable(); + LayoutUnit maxColumnHeight = availableHeight ? availableHeight : RenderFlowThread::maxLogicalHeight(); + if (!multicolStyle->logicalMaxHeight().isUndefined()) { + LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight(multicolStyle->logicalMaxHeight(), -1); + if (logicalMaxHeight != -1 && maxColumnHeight > logicalMaxHeight) + maxColumnHeight = logicalMaxHeight; + } + return heightAdjustedForSetOffset(maxColumnHeight); +} + LayoutUnit RenderMultiColumnSet::columnGap() const { - // FIXME: Eventually we will cache the column gap when the widths of columns start varying, but for now we just - // go to the parent block to get the gap. - RenderMultiColumnBlock* parentBlock = toRenderMultiColumnBlock(parent()); + RenderBlockFlow* parentBlock = multiColumnBlockFlow(); if (parentBlock->style()->hasNormalColumnGap()) return parentBlock->style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins. return parentBlock->style()->columnGap(); } -unsigned RenderMultiColumnSet::columnCount() const +unsigned RenderMultiColumnSet::actualColumnCount() const { // We must always return a value of 1 or greater. Column count = 0 is a meaningless situation, // and will confuse and cause problems in other parts of the code. - if (!computedColumnHeight()) + if (!pageLogicalHeight()) return 1; // Our portion rect determines our column count. We have as many columns as needed to fit all the content. LayoutUnit logicalHeightInColumns = flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().height() : flowThreadPortionRect().width(); - unsigned count = ceil(static_cast<float>(logicalHeightInColumns) / computedColumnHeight()); + if (!logicalHeightInColumns) + return 1; + + unsigned count = ceil(logicalHeightInColumns.toFloat() / pageLogicalHeight().toFloat()); ASSERT(count >= 1); return count; } LayoutRect RenderMultiColumnSet::columnRectAt(unsigned index) const { - LayoutUnit colLogicalWidth = computedColumnWidth(); - LayoutUnit colLogicalHeight = computedColumnHeight(); + LayoutUnit colLogicalWidth = pageLogicalWidth(); + LayoutUnit colLogicalHeight = pageLogicalHeight(); LayoutUnit colLogicalTop = borderBefore() + paddingBefore(); LayoutUnit colLogicalLeft = borderAndPaddingLogicalLeft(); LayoutUnit colGap = columnGap(); @@ -249,20 +360,20 @@ unsigned RenderMultiColumnSet::columnIndexAtOffset(LayoutUnit offset, ColumnInde if (mode == ClampToExistingColumns) { LayoutUnit flowThreadLogicalBottom = isHorizontalWritingMode() ? portionRect.maxY() : portionRect.maxX(); if (offset >= flowThreadLogicalBottom) - return columnCount() - 1; + return actualColumnCount() - 1; } // Just divide by the column height to determine the correct column. - return static_cast<float>(offset - flowThreadLogicalTop) / computedColumnHeight(); + return (offset - flowThreadLogicalTop).toFloat() / pageLogicalHeight().toFloat(); } LayoutRect RenderMultiColumnSet::flowThreadPortionRectAt(unsigned index) const { LayoutRect portionRect = flowThreadPortionRect(); if (isHorizontalWritingMode()) - portionRect = LayoutRect(portionRect.x(), portionRect.y() + index * computedColumnHeight(), portionRect.width(), computedColumnHeight()); + portionRect = LayoutRect(portionRect.x(), portionRect.y() + index * pageLogicalHeight(), portionRect.width(), pageLogicalHeight()); else - portionRect = LayoutRect(portionRect.x() + index * computedColumnHeight(), portionRect.y(), computedColumnHeight(), portionRect.height()); + portionRect = LayoutRect(portionRect.x() + index * pageLogicalHeight(), portionRect.y(), pageLogicalHeight(), portionRect.height()); return portionRect; } @@ -308,7 +419,7 @@ void RenderMultiColumnSet::paintObject(PaintInfo& paintInfo, const LayoutPoint& if (style()->visibility() != VISIBLE) return; - RenderBlock::paintObject(paintInfo, paintOffset); + RenderBlockFlow::paintObject(paintInfo, paintOffset); // FIXME: Right now we're only painting in the foreground phase. // Columns should technically respect phases and allow for background/float/foreground overlap etc., just like @@ -326,7 +437,7 @@ void RenderMultiColumnSet::paintColumnRules(PaintInfo& paintInfo, const LayoutPo if (paintInfo.context->paintingDisabled()) return; - RenderStyle* blockStyle = toRenderMultiColumnBlock(parent())->style(); + RenderStyle* blockStyle = multiColumnBlockFlow()->style(); const Color& ruleColor = resolveColor(blockStyle, CSSPropertyWebkitColumnRuleColor); bool ruleTransparent = blockStyle->columnRuleIsTransparent(); EBorderStyle ruleStyle = blockStyle->columnRuleStyle(); @@ -336,7 +447,7 @@ void RenderMultiColumnSet::paintColumnRules(PaintInfo& paintInfo, const LayoutPo if (!renderRule) return; - unsigned colCount = columnCount(); + unsigned colCount = actualColumnCount(); if (colCount <= 1) return; @@ -346,7 +457,7 @@ void RenderMultiColumnSet::paintColumnRules(PaintInfo& paintInfo, const LayoutPo LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : contentLogicalWidth(); LayoutUnit ruleAdd = borderAndPaddingLogicalLeft(); LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : contentLogicalWidth(); - LayoutUnit inlineDirectionSize = computedColumnWidth(); + LayoutUnit inlineDirectionSize = pageLogicalWidth(); BoxSide boxSide = isHorizontalWritingMode() ? leftToRight ? BSLeft : BSRight : leftToRight ? BSTop : BSBottom; @@ -398,7 +509,7 @@ void RenderMultiColumnSet::repaintFlowThreadContent(const LayoutRect& repaintRec unsigned endColumn = columnIndexAtOffset(repaintLogicalBottom); LayoutUnit colGap = columnGap(); - unsigned colCount = columnCount(); + unsigned colCount = actualColumnCount(); for (unsigned i = startColumn; i <= endColumn; i++) { LayoutRect colRect = columnRectAt(i); @@ -451,9 +562,9 @@ void RenderMultiColumnSet::collectLayerFragments(LayerFragments& fragments, cons unsigned startColumn = columnIndexAtOffset(layerLogicalTop); unsigned endColumn = columnIndexAtOffset(layerLogicalBottom); - LayoutUnit colLogicalWidth = computedColumnWidth(); + LayoutUnit colLogicalWidth = pageLogicalWidth(); LayoutUnit colGap = columnGap(); - unsigned colCount = columnCount(); + unsigned colCount = actualColumnCount(); for (unsigned i = startColumn; i <= endColumn; i++) { // Get the portion of the flow thread that corresponds to this column. @@ -507,6 +618,18 @@ void RenderMultiColumnSet::collectLayerFragments(LayerFragments& fragments, cons } } +void RenderMultiColumnSet::addOverflowFromChildren() +{ + unsigned colCount = actualColumnCount(); + if (!colCount) + return; + + LayoutRect lastRect = columnRectAt(colCount - 1); + addLayoutOverflow(lastRect); + if (!hasOverflowClip()) + addVisualOverflow(lastRect); +} + const char* RenderMultiColumnSet::renderName() const { return "RenderMultiColumnSet"; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnSet.h b/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnSet.h index 3ebfc5e9c56..16c12faaf36 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnSet.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderMultiColumnSet.h @@ -27,65 +27,75 @@ #ifndef RenderMultiColumnSet_h #define RenderMultiColumnSet_h -#include "core/rendering/RenderRegionSet.h" +#include "core/rendering/RenderMultiColumnFlowThread.h" +#include "core/rendering/RenderRegion.h" +#include "wtf/Vector.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. +// 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 sets are inserted as anonymous children of the actual multicol container (i.e. the +// renderer whose style computes to non-auto column-count and/or column-width). // -// 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 FINAL : public RenderRegionSet { +// Being a "region", a column set has no children on its own, but is merely used to slice a portion +// of the tall "single-column" flow thread into actual columns visually, to convert from flow thread +// coordinates to visual ones. It is in charge of both positioning columns correctly relatively to +// the parent multicol container, and to calculate the correct translation for each column's +// contents, and to paint any rules between them. RenderMultiColumnSet objects are used for +// painting, hit testing, and any other type of operation that requires mapping from flow thread +// coordinates to visual coordinates. +// +// Column spans result in the creation of new column sets, since a spanning renderer has to be +// placed in between the column sets that come before and after the span. +class RenderMultiColumnSet FINAL : public RenderRegion { public: - static RenderMultiColumnSet* createAnonymous(RenderFlowThread*); + enum BalancedHeightCalculation { GuessFromFlowThreadPortion, StretchBySpaceShortage }; + + static RenderMultiColumnSet* createAnonymous(RenderFlowThread*, RenderStyle* parentStyle); virtual bool isRenderMultiColumnSet() const OVERRIDE { return true; } - unsigned computedColumnCount() const { return m_computedColumnCount; } - LayoutUnit computedColumnWidth() const { return m_computedColumnWidth; } - LayoutUnit computedColumnHeight() const { return m_computedColumnHeight; } + virtual LayoutUnit pageLogicalWidth() const OVERRIDE FINAL { return flowThread()->logicalWidth(); } + virtual LayoutUnit pageLogicalHeight() const OVERRIDE FINAL { return m_columnHeight; } - void setComputedColumnWidthAndCount(LayoutUnit width, unsigned count) + RenderBlockFlow* multiColumnBlockFlow() const { return toRenderBlockFlow(parent()); } + RenderMultiColumnFlowThread* multiColumnFlowThread() const { - m_computedColumnWidth = width; - m_computedColumnCount = count; + ASSERT_WITH_SECURITY_IMPLICATION(!flowThread() || flowThread()->isRenderMultiColumnFlowThread()); + return static_cast<RenderMultiColumnFlowThread*>(flowThread()); } + RenderMultiColumnSet* nextSiblingMultiColumnSet() const; + RenderMultiColumnSet* previousSiblingMultiColumnSet() const; + + LayoutUnit logicalTopInFlowThread() const { return isHorizontalWritingMode() ? flowThreadPortionRect().y() : flowThreadPortionRect().x(); } + LayoutUnit logicalBottomInFlowThread() const { return isHorizontalWritingMode() ? flowThreadPortionRect().maxY() : flowThreadPortionRect().maxX(); } + + LayoutUnit logicalHeightInFlowThread() const { return isHorizontalWritingMode() ? flowThreadPortionRect().height() : flowThreadPortionRect().width(); } + + // The used CSS value of column-count, i.e. how many columns there are room for without overflowing. + unsigned usedColumnCount() const { return multiColumnFlowThread()->columnCount(); } + + // Find the column that contains the given block offset, and return the translation needed to + // get from flow thread coordinates to visual coordinates. + LayoutSize flowThreadTranslationAtOffset(LayoutUnit) const; + LayoutUnit heightAdjustedForSetOffset(LayoutUnit height) const; void updateMinimumColumnHeight(LayoutUnit height) { m_minimumColumnHeight = std::max(height, m_minimumColumnHeight); } LayoutUnit minimumColumnHeight() const { return m_minimumColumnHeight; } - unsigned forcedBreaksCount() const { return m_forcedBreaksCount; } - LayoutUnit forcedBreakOffset() const { return m_forcedBreakOffset; } - LayoutUnit maximumDistanceBetweenForcedBreaks() const { return m_maximumDistanceBetweenForcedBreaks; } - void clearForcedBreaks() - { - m_forcedBreaksCount = 0; - m_maximumDistanceBetweenForcedBreaks = 0; - m_forcedBreakOffset = 0; - } - void addForcedBreak(LayoutUnit offsetFromFirstPage) - { - ASSERT(!computedColumnHeight()); - LayoutUnit distanceFromLastBreak = offsetFromFirstPage - m_forcedBreakOffset; - if (!distanceFromLastBreak) - return; - m_forcedBreaksCount++; - m_maximumDistanceBetweenForcedBreaks = std::max(m_maximumDistanceBetweenForcedBreaks, distanceFromLastBreak); - m_forcedBreakOffset = offsetFromFirstPage; - } + // Add a content run, specified by its end position. A content run is appended at every + // forced/explicit break and at the end of the column set. The content runs are used to + // determine where implicit/soft breaks will occur, in order to calculate an initial column + // height. + void addContentRun(LayoutUnit endOffsetFromFirstPage); - // Calculate the column height when contents are supposed to be balanced. If 'initial' is set, - // guess an initial column height; otherwise, stretch the column height a tad. Return true if - // column height changed and another layout pass is required. - bool calculateBalancedHeight(bool initial); + // (Re-)calculate the column height if it's auto. + bool recalculateColumnHeight(BalancedHeightCalculation); // Record space shortage (the amount of space that would have been enough to prevent some // element from being moved to the next column) at a column break. The smallest amount of space @@ -93,9 +103,12 @@ public: // after layout that the columns weren't tall enough. void recordSpaceShortage(LayoutUnit spaceShortage); - virtual void updateLogicalWidth() OVERRIDE; + // Reset previously calculated column height. Will mark for layout if needed. + void resetColumnHeight(); - void prepareForLayout(); + // Expand this set's flow thread portion rectangle to contain all trailing flow thread + // overflow. Only to be called on the last set. + void expandToEncompassFlowThreadContentsIfNeeded(); private: RenderMultiColumnSet(RenderFlowThread*); @@ -104,29 +117,26 @@ private: virtual void paintObject(PaintInfo&, const LayoutPoint& paintOffset) OVERRIDE; - virtual LayoutUnit pageLogicalWidth() const OVERRIDE { return m_computedColumnWidth; } - virtual LayoutUnit pageLogicalHeight() const OVERRIDE { return m_computedColumnHeight; } - virtual LayoutUnit pageLogicalTopForOffset(LayoutUnit offset) const OVERRIDE; - // FIXME: This will change once we have column sets constrained by enclosing pages, etc. - virtual LayoutUnit logicalHeightOfAllFlowThreadContent() const OVERRIDE { return m_computedColumnHeight; } - - // FIXME: For now we return false, but it's likely we will leverage the auto height region code to do column - // balancing. That's why we have an override of this function that is distinct from RenderRegionSet's override. - virtual bool shouldHaveAutoLogicalHeight() const OVERRIDE { return false; } + virtual LayoutUnit logicalHeightOfAllFlowThreadContent() const OVERRIDE { return logicalHeightInFlowThread(); } virtual void repaintFlowThreadContent(const LayoutRect& repaintRect) const OVERRIDE; virtual void collectLayerFragments(LayerFragments&, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect) OVERRIDE; - virtual const char* renderName() const; + virtual void addOverflowFromChildren() OVERRIDE; + + virtual const char* renderName() const OVERRIDE; void paintColumnRules(PaintInfo&, const LayoutPoint& paintOffset); + LayoutUnit calculateMaxColumnHeight() const; LayoutUnit columnGap() const; LayoutRect columnRectAt(unsigned index) const; - unsigned columnCount() const; + + // The "CSS actual" value of column-count. This includes overflowing columns, if any. + unsigned actualColumnCount() const; LayoutRect flowThreadPortionRectAt(unsigned index) const; LayoutRect flowThreadPortionOverflowRect(const LayoutRect& flowThreadPortion, unsigned index, unsigned colCount, LayoutUnit colGap) const; @@ -139,17 +149,50 @@ private: void setAndConstrainColumnHeight(LayoutUnit); - unsigned m_computedColumnCount; - LayoutUnit m_computedColumnWidth; - LayoutUnit m_computedColumnHeight; + // Return the index of the content run with the currently tallest columns, taking all implicit + // breaks assumed so far into account. + unsigned findRunWithTallestColumns() const; + + // Given the current list of content runs, make assumptions about where we need to insert + // implicit breaks (if there's room for any at all; depending on the number of explicit breaks), + // and store the results. This is needed in order to balance the columns. + void distributeImplicitBreaks(); + + LayoutUnit calculateColumnHeight(BalancedHeightCalculation) const; + + LayoutUnit m_columnHeight; // The following variables are used when balancing the column set. LayoutUnit m_maxColumnHeight; // Maximum column height allowed. LayoutUnit m_minSpaceShortage; // The smallest amout of space shortage that caused a column break. LayoutUnit m_minimumColumnHeight; - unsigned m_forcedBreaksCount; // FIXME: We will ultimately need to cache more information to balance around forced breaks properly. - LayoutUnit m_maximumDistanceBetweenForcedBreaks; - LayoutUnit m_forcedBreakOffset; + + // A run of content without explicit (forced) breaks; i.e. a flow thread portion between two + // explicit breaks, between flow thread start and an explicit break, between an explicit break + // and flow thread end, or, in cases when there are no explicit breaks at all: between flow + // thread portion start and flow thread portion end. We need to know where the explicit breaks + // are, in order to figure out where the implicit breaks will end up, so that we get the columns + // properly balanced. A content run starts out as representing one single column, and will + // represent one additional column for each implicit break "inserted" there. + class ContentRun { + public: + ContentRun(LayoutUnit breakOffset) + : m_breakOffset(breakOffset) + , m_assumedImplicitBreaks(0) { } + + unsigned assumedImplicitBreaks() const { return m_assumedImplicitBreaks; } + void assumeAnotherImplicitBreak() { m_assumedImplicitBreaks++; } + LayoutUnit breakOffset() const { return m_breakOffset; } + + // Return the column height that this content run would require, considering the implicit + // breaks assumed so far. + LayoutUnit columnLogicalHeight(LayoutUnit startOffset) const { return ceilf((m_breakOffset - startOffset).toFloat() / float(m_assumedImplicitBreaks + 1)); } + + private: + LayoutUnit m_breakOffset; // Flow thread offset where this run ends. + unsigned m_assumedImplicitBreaks; // Number of implicit breaks in this run assumed so far. + }; + Vector<ContentRun, 1> m_contentRuns; }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderMultiColumnSet, isRenderMultiColumnSet()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderNamedFlowFragment.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderNamedFlowFragment.cpp deleted file mode 100644 index 5a754e99f82..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderNamedFlowFragment.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2013 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 "core/rendering/RenderNamedFlowFragment.h" - -#include "core/rendering/FlowThreadController.h" -#include "core/rendering/RenderBoxRegionInfo.h" -#include "core/rendering/RenderFlowThread.h" -#include "core/rendering/RenderNamedFlowThread.h" -#include "core/rendering/RenderView.h" - -using namespace std; - -namespace WebCore { - -RenderNamedFlowFragment::RenderNamedFlowFragment() - : RenderRegion(0, 0) -{ -} - -RenderNamedFlowFragment::~RenderNamedFlowFragment() -{ -} - -RenderNamedFlowFragment* RenderNamedFlowFragment::createAnonymous(Document* document) -{ - RenderNamedFlowFragment* region = new RenderNamedFlowFragment(); - region->setDocumentForAnonymous(document); - return region; -} - -void RenderNamedFlowFragment::setStyleForNamedFlowFragment(const RenderStyle* parentStyle) -{ - RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parentStyle, BLOCK); - - newStyle->setFlowThread(parentStyle->flowThread()); - newStyle->setRegionThread(parentStyle->regionThread()); - newStyle->setRegionFragment(parentStyle->regionFragment()); - newStyle->setShapeInside(parentStyle->shapeInside()); - newStyle->setOverflowX(parentStyle->overflowX()); - newStyle->setOverflowY(parentStyle->overflowY()); - - setStyle(newStyle.release()); -} - -void RenderNamedFlowFragment::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) -{ - RenderRegion::styleDidChange(diff, oldStyle); - - if (parent() && parent()->needsLayout()) - setNeedsLayout(); -} - -// FIXME: flex items as regions with flex-basis: 0 inside a flex container -// with flex-direction: column should not be treated as auto-height regions -bool RenderNamedFlowFragment::shouldHaveAutoLogicalHeight() const -{ - ASSERT(parent()); - - RenderStyle* styleToUse = parent()->style(); - bool hasSpecifiedEndpointsForHeight = styleToUse->logicalTop().isSpecified() && styleToUse->logicalBottom().isSpecified(); - bool hasAnchoredEndpointsForHeight = isOutOfFlowPositioned() && hasSpecifiedEndpointsForHeight; - bool hasAutoHeightStyle = styleToUse->logicalHeight().isAuto() - || styleToUse->logicalHeight().isFitContent() - || styleToUse->logicalHeight().isMaxContent() - || styleToUse->logicalHeight().isMinContent(); - return hasAutoHeightStyle && !hasAnchoredEndpointsForHeight; -} - -LayoutUnit RenderNamedFlowFragment::maxPageLogicalHeight() const -{ - ASSERT(m_flowThread); - ASSERT(hasAutoLogicalHeight() && !m_flowThread->inConstrainedLayoutPhase()); - ASSERT(isAnonymous()); - ASSERT(parent()); - - RenderStyle* styleToUse = parent()->style(); - return styleToUse->logicalMaxHeight().isUndefined() ? RenderFlowThread::maxLogicalHeight() : toRenderBlock(parent())->computeReplacedLogicalHeightUsing(styleToUse->logicalMaxHeight()); -} - -} diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderNamedFlowFragment.h b/chromium/third_party/WebKit/Source/core/rendering/RenderNamedFlowFragment.h deleted file mode 100644 index 79e4d7ceb63..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderNamedFlowFragment.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2013 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 RenderNamedFlowFragment_h -#define RenderNamedFlowFragment_h - -#include "core/rendering/RenderRegion.h" - -namespace WebCore { - -class Element; -class RenderStyle; - -// RenderNamedFlowFragment represents a region that is responsible for the fragmentation of -// the RenderNamedFlowThread content. -// -// A RenderNamedFlowFragment object is created as an anonymous child for a RenderBlockFlow object -// that has a valid -webkit-flow-from property. -// -// This allows a non-replaced block to behave like a region if needed, following the CSSRegions specification: -// http://dev.w3.org/csswg/css-regions/#the-flow-from-property. -// list-item, table-caption, table-cell can become regions in addition to block | inline-block. - -class RenderNamedFlowFragment FINAL : public RenderRegion { -public: - virtual ~RenderNamedFlowFragment(); - static RenderNamedFlowFragment* createAnonymous(Document*); - - void setStyleForNamedFlowFragment(const RenderStyle*); - - virtual bool isRenderNamedFlowFragment() const OVERRIDE { return true; } - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; - - virtual LayoutUnit maxPageLogicalHeight() const OVERRIDE; - -protected: - RenderNamedFlowFragment(); - -private: - virtual bool shouldHaveAutoLogicalHeight() const OVERRIDE; - virtual const char* renderName() const OVERRIDE { return "RenderNamedFlowFragment"; } -}; - -DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderNamedFlowFragment, isRenderNamedFlowFragment()); - -} - -#endif // RenderNamedFlowFragment_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderNamedFlowThread.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderNamedFlowThread.cpp deleted file mode 100644 index 72049543c9d..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderNamedFlowThread.cpp +++ /dev/null @@ -1,730 +0,0 @@ -/* - * 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 "core/rendering/RenderNamedFlowThread.h" - -#include "RuntimeEnabledFeatures.h" -#include "bindings/v8/ExceptionStatePlaceholder.h" -#include "core/dom/NamedFlow.h" -#include "core/dom/NodeRenderingTraversal.h" -#include "core/dom/NodeTraversal.h" -#include "core/dom/Position.h" -#include "core/dom/Range.h" -#include "core/dom/Text.h" -#include "core/inspector/InspectorInstrumentation.h" -#include "core/rendering/FlowThreadController.h" -#include "core/rendering/InlineTextBox.h" -#include "core/rendering/RenderInline.h" -#include "core/rendering/RenderRegion.h" -#include "core/rendering/RenderText.h" -#include "core/rendering/RenderView.h" - -namespace WebCore { - -RenderNamedFlowThread* RenderNamedFlowThread::createAnonymous(Document* document, PassRefPtr<NamedFlow> namedFlow) -{ - ASSERT(RuntimeEnabledFeatures::cssRegionsEnabled()); - RenderNamedFlowThread* renderer = new RenderNamedFlowThread(namedFlow); - renderer->setDocumentForAnonymous(document); - return renderer; -} - -RenderNamedFlowThread::RenderNamedFlowThread(PassRefPtr<NamedFlow> namedFlow) - : m_overset(true) - , m_namedFlow(namedFlow) - , m_regionLayoutUpdateEventTimer(this, &RenderNamedFlowThread::regionLayoutUpdateEventTimerFired) - , m_regionOversetChangeEventTimer(this, &RenderNamedFlowThread::regionOversetChangeEventTimerFired) -{ -} - -RenderNamedFlowThread::~RenderNamedFlowThread() -{ - // The flow thread can be destroyed without unregistering the content nodes if the document is destroyed. - // This can lead to problems because the nodes are still marked as belonging to a flow thread. - clearContentNodes(); - - // Also leave the NamedFlow object in a consistent state by calling mark for destruction. - setMarkForDestruction(); -} - -const char* RenderNamedFlowThread::renderName() const -{ - return "RenderNamedFlowThread"; -} - -void RenderNamedFlowThread::clearContentNodes() -{ - for (NamedFlowContentNodes::iterator it = m_contentNodes.begin(); it != m_contentNodes.end(); ++it) { - Node* contentNode = *it; - - ASSERT(contentNode && contentNode->isElementNode()); - ASSERT(contentNode->inNamedFlow()); - ASSERT(contentNode->document() == document()); - - contentNode->clearInNamedFlow(); - } - - m_contentNodes.clear(); -} - -void RenderNamedFlowThread::updateWritingMode() -{ - RenderRegion* firstRegion = m_regionList.first(); - if (!firstRegion) - return; - if (style()->writingMode() == firstRegion->style()->writingMode()) - return; - - // The first region defines the principal writing mode for the entire flow. - RefPtr<RenderStyle> newStyle = RenderStyle::clone(style()); - newStyle->setWritingMode(firstRegion->style()->writingMode()); - setStyle(newStyle.release()); -} - -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) -{ - // 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. - - Node* childNode = newChild->node(); - - // Do not add anonymous objects. - if (!childNode) - return; - - ASSERT(childNode->isElementNode()); - - RenderObject* beforeChild = nextRendererForNode(childNode); - 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).key; - 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); - - ASSERT(firstRegion->generatingNodeForRegion()); - ASSERT(secondRegion->generatingNodeForRegion()); - - // If the regions belong to different nodes, compare their position in the DOM. - if (firstRegion->generatingNodeForRegion() != secondRegion->generatingNodeForRegion()) { - unsigned short position = firstRegion->generatingNodeForRegion()->compareDocumentPosition(secondRegion->generatingNodeForRegion()); - - // If the second region is contained in the first one, the first region is "less" if it's :before. - if (position & Node::DOCUMENT_POSITION_CONTAINED_BY) { - ASSERT(secondRegion->style()->styleType() == NOPSEUDO); - return firstRegion->style()->styleType() == BEFORE; - } - - // If the second region contains the first region, the first region is "less" if the second is :after. - if (position & Node::DOCUMENT_POSITION_CONTAINS) { - ASSERT(firstRegion->style()->styleType() == NOPSEUDO); - return secondRegion->style()->styleType() == AFTER; - } - - return (position & Node::DOCUMENT_POSITION_FOLLOWING); - } - - // FIXME: Currently it's not possible for an element to be both a region and have pseudo-children. The case is covered anyway. - switch (firstRegion->style()->styleType()) { - case BEFORE: - // The second region can be the node or the after pseudo-element (before is smaller than any of those). - return true; - case AFTER: - // The second region can be the node or the before pseudo-element (after is greater than any of those). - return false; - case NOPSEUDO: - // The second region can either be the before or the after pseudo-element (the node is only smaller than the after pseudo-element). - return firstRegion->style()->styleType() == AFTER; - default: - break; - } - - ASSERT_NOT_REACHED(); - return true; -} - -// This helper function adds a region to a list preserving the order property of the list. -static void addRegionToList(RenderRegionList& regionList, RenderRegion* renderRegion) -{ - if (regionList.isEmpty()) { - regionList.add(renderRegion); - } else { - // Find the first region "greater" than renderRegion. - RenderRegionList::iterator it = regionList.begin(); - while (it != regionList.end() && !compareRenderRegions(renderRegion, *it)) - ++it; - regionList.insertBefore(it, renderRegion); - } -} - -void RenderNamedFlowThread::addRegionToNamedFlowThread(RenderRegion* renderRegion) -{ - ASSERT(renderRegion); - ASSERT(!renderRegion->isValid()); - - if (renderRegion->parentNamedFlowThread()) - addDependencyOnFlowThread(renderRegion->parentNamedFlowThread()); - - renderRegion->setIsValid(true); - addRegionToList(m_regionList, renderRegion); - - if (m_regionList.first() == renderRegion) - updateWritingMode(); -} - -void RenderNamedFlowThread::addRegionToThread(RenderRegion* renderRegion) -{ - ASSERT(renderRegion); - ASSERT(!renderRegion->isValid()); - - resetMarkForDestruction(); - - if (renderRegion->parentNamedFlowThread() && renderRegion->parentNamedFlowThread()->dependsOn(this)) { - // The order of invalid regions is irrelevant. - m_invalidRegionList.add(renderRegion); - // Register ourself to get a notification when the state changes. - renderRegion->parentNamedFlowThread()->m_observerThreadsSet.add(this); - return; - } - - addRegionToNamedFlowThread(renderRegion); - - invalidateRegions(); -} - -void RenderNamedFlowThread::removeRegionFromThread(RenderRegion* renderRegion) -{ - ASSERT(renderRegion); - - if (renderRegion->parentNamedFlowThread()) { - if (!renderRegion->isValid()) { - ASSERT(m_invalidRegionList.contains(renderRegion)); - m_invalidRegionList.remove(renderRegion); - 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()); - } - - ASSERT(m_regionList.contains(renderRegion)); - bool wasFirst = m_regionList.first() == renderRegion; - m_regionList.remove(renderRegion); - - if (canBeDestroyed()) - setMarkForDestruction(); - - // After removing all the regions in the flow the following layout needs to dispatch the regionLayoutUpdate event - if (m_regionList.isEmpty()) - setDispatchRegionLayoutUpdateEvent(true); - else if (wasFirst) - updateWritingMode(); - - invalidateRegions(); -} - -void RenderNamedFlowThread::regionChangedWritingMode(RenderRegion* region) -{ - if (m_regionList.first() == region) - updateWritingMode(); -} - -void RenderNamedFlowThread::computeOversetStateForRegions(LayoutUnit oldClientAfterEdge) -{ - LayoutUnit height = oldClientAfterEdge; - - // FIXME: the visual overflow of middle region (if it is the last one to contain any content in a render flow thread) - // might not be taken into account because the render flow thread height is greater that that regions height + its visual overflow - // because of how computeLogicalHeight is implemented for RenderFlowThread (as a sum of all regions height). - // This means that the middle region will be marked as fit (even if it has visual overflow flowing into the next region) - if (hasRenderOverflow() - && ( (isHorizontalWritingMode() && visualOverflowRect().maxY() > clientBoxRect().maxY()) - || (!isHorizontalWritingMode() && visualOverflowRect().maxX() > clientBoxRect().maxX()))) - height = isHorizontalWritingMode() ? visualOverflowRect().maxY() : visualOverflowRect().maxX(); - - RenderRegion* lastReg = lastRegion(); - for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { - RenderRegion* region = *iter; - LayoutUnit flowMin = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().y() : region->flowThreadPortionRect().x()); - LayoutUnit flowMax = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().maxY() : region->flowThreadPortionRect().maxX()); - RegionOversetState previousState = region->regionOversetState(); - RegionOversetState state = RegionFit; - if (flowMin <= 0) - state = RegionEmpty; - if (flowMax > 0 && region == lastReg) - state = RegionOverset; - region->setRegionOversetState(state); - // determine whether the NamedFlow object should dispatch a regionLayoutUpdate event - // FIXME: currently it cannot determine whether a region whose regionOverset state remained either "fit" or "overset" has actually - // changed, so it just assumes that the NamedFlow should dispatch the event - if (previousState != state - || state == RegionFit - || state == RegionOverset) - setDispatchRegionLayoutUpdateEvent(true); - - if (previousState != state) - setDispatchRegionOversetChangeEvent(true); - } - - // If the number of regions has changed since we last computed the overset property, schedule the regionOversetChange event. - if (previousRegionCountChanged()) { - setDispatchRegionOversetChangeEvent(true); - updatePreviousRegionCount(); - } - - // With the regions overflow state computed we can also set the overset flag for the named flow. - // If there are no valid regions in the chain, overset is true. - m_overset = lastReg ? lastReg->regionOversetState() == RegionOverset : true; -} - -void RenderNamedFlowThread::checkInvalidRegions() -{ - Vector<RenderRegion*> newValidRegions; - for (RenderRegionList::iterator iter = m_invalidRegionList.begin(); iter != m_invalidRegionList.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->parentNamedFlowThread()->dependsOn(this)) - continue; - - newValidRegions.append(region); - } - - for (Vector<RenderRegion*>::iterator iter = newValidRegions.begin(); iter != newValidRegions.end(); ++iter) { - RenderRegion* region = *iter; - m_invalidRegionList.remove(region); - region->parentNamedFlowThread()->m_observerThreadsSet.remove(this); - addRegionToNamedFlowThread(region); - } - - if (!newValidRegions.isEmpty()) - 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).key; - if (list.contains(flowThread)) - continue; - flowThread->pushDependencies(list); - list.add(flowThread); - } -} - -// 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()); - ASSERT(contentNode->document() == document()); - - contentNode->setInNamedFlow(); - - resetMarkForDestruction(); - - // 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()); - ASSERT(contentNode->document() == document()); - - contentNode->clearInNamedFlow(); - m_contentNodes.remove(contentNode); - - if (canBeDestroyed()) - setMarkForDestruction(); -} - -const AtomicString& RenderNamedFlowThread::flowThreadName() const -{ - return m_namedFlow->name(); -} - -bool RenderNamedFlowThread::isChildAllowed(RenderObject* child, RenderStyle* style) const -{ - if (!child->node()) - return true; - - ASSERT(child->node()->isElementNode()); - Node* originalParent = NodeRenderingTraversal::parent(child->node()); - if (!originalParent || !originalParent->renderer()) - return true; - - return originalParent->renderer()->isChildAllowed(child, style); -} - -void RenderNamedFlowThread::dispatchRegionLayoutUpdateEvent() -{ - RenderFlowThread::dispatchRegionLayoutUpdateEvent(); - InspectorInstrumentation::didUpdateRegionLayout(&document(), m_namedFlow.get()); - - if (!m_regionLayoutUpdateEventTimer.isActive() && m_namedFlow->hasEventListeners()) - m_regionLayoutUpdateEventTimer.startOneShot(0); -} - -void RenderNamedFlowThread::dispatchRegionOversetChangeEvent() -{ - RenderFlowThread::dispatchRegionOversetChangeEvent(); - InspectorInstrumentation::didChangeRegionOverset(&document(), m_namedFlow.get()); - - if (!m_regionOversetChangeEventTimer.isActive() && m_namedFlow->hasEventListeners()) - m_regionOversetChangeEventTimer.startOneShot(0); -} - -void RenderNamedFlowThread::regionLayoutUpdateEventTimerFired(Timer<RenderNamedFlowThread>*) -{ - ASSERT(m_namedFlow); - - m_namedFlow->dispatchRegionLayoutUpdateEvent(); -} - -void RenderNamedFlowThread::regionOversetChangeEventTimerFired(Timer<RenderNamedFlowThread>*) -{ - ASSERT(m_namedFlow); - - m_namedFlow->dispatchRegionOversetChangeEvent(); -} - -void RenderNamedFlowThread::setMarkForDestruction() -{ - if (m_namedFlow->flowState() == NamedFlow::FlowStateNull) - return; - - m_namedFlow->setRenderer(0); - // After this call ends, the renderer can be safely destroyed. - // The NamedFlow object may outlive its renderer if it's referenced from a script and may be reatached to one if the named flow is recreated in the stylesheet. -} - -void RenderNamedFlowThread::resetMarkForDestruction() -{ - if (m_namedFlow->flowState() == NamedFlow::FlowStateCreated) - return; - - m_namedFlow->setRenderer(this); -} - -bool RenderNamedFlowThread::isMarkedForDestruction() const -{ - // Flow threads in the "NULL" state can be destroyed. - return m_namedFlow->flowState() == NamedFlow::FlowStateNull; -} - -static bool isContainedInNodes(Vector<Node*> others, Node* node) -{ - for (size_t i = 0; i < others.size(); i++) { - Node* other = others.at(i); - if (other->contains(node)) - return true; - } - return false; -} - -static bool boxIntersectsRegion(LayoutUnit logicalTopForBox, LayoutUnit logicalBottomForBox, LayoutUnit logicalTopForRegion, LayoutUnit logicalBottomForRegion) -{ - bool regionIsEmpty = logicalBottomForRegion != LayoutUnit::max() && logicalTopForRegion != LayoutUnit::min() - && (logicalBottomForRegion - logicalTopForRegion) <= 0; - return (logicalBottomForBox - logicalTopForBox) > 0 - && !regionIsEmpty - && logicalTopForBox < logicalBottomForRegion && logicalTopForRegion < logicalBottomForBox; -} - -// Retrieve the next node to be visited while computing the ranges inside a region. -static Node* nextNodeInsideContentNode(const Node& currNode, const Node* contentNode) -{ - ASSERT(contentNode && contentNode->inNamedFlow()); - - if (currNode.renderer() && currNode.renderer()->isSVGRoot()) - return NodeTraversal::nextSkippingChildren(currNode, contentNode); - return NodeTraversal::next(currNode, contentNode); -} - -void RenderNamedFlowThread::getRanges(Vector<RefPtr<Range> >& rangeObjects, const RenderRegion* region) const -{ - LayoutUnit logicalTopForRegion; - LayoutUnit logicalBottomForRegion; - - // extend the first region top to contain everything up to its logical height - if (region->isFirstRegion()) - logicalTopForRegion = LayoutUnit::min(); - else - logicalTopForRegion = region->logicalTopForFlowThreadContent(); - - // extend the last region to contain everything above its y() - if (region->isLastRegion()) - logicalBottomForRegion = LayoutUnit::max(); - else - logicalBottomForRegion = region->logicalBottomForFlowThreadContent(); - - Vector<Node*> nodes; - // eliminate the contentNodes that are descendants of other contentNodes - for (NamedFlowContentNodes::const_iterator it = contentNodes().begin(); it != contentNodes().end(); ++it) { - Node* node = *it; - if (!isContainedInNodes(nodes, node)) - nodes.append(node); - } - - for (size_t i = 0; i < nodes.size(); i++) { - Node* contentNode = nodes.at(i); - if (!contentNode->renderer()) - continue; - - RefPtr<Range> range = Range::create(contentNode->document()); - bool foundStartPosition = false; - bool startsAboveRegion = true; - bool endsBelowRegion = true; - bool skipOverOutsideNodes = false; - Node* lastEndNode = 0; - - for (Node* node = contentNode; node; node = nextNodeInsideContentNode(*node, contentNode)) { - RenderObject* renderer = node->renderer(); - if (!renderer) - continue; - - LayoutRect boundingBox; - if (renderer->isRenderInline()) { - boundingBox = toRenderInline(renderer)->linesBoundingBox(); - } else if (renderer->isText()) { - boundingBox = toRenderText(renderer)->linesBoundingBox(); - } else { - boundingBox = toRenderBox(renderer)->frameRect(); - if (toRenderBox(renderer)->isRelPositioned()) - boundingBox.move(toRenderBox(renderer)->relativePositionLogicalOffset()); - } - - LayoutUnit offsetTop = renderer->containingBlock()->offsetFromLogicalTopOfFirstPage(); - const LayoutPoint logicalOffsetFromTop(isHorizontalWritingMode() ? LayoutUnit() : offsetTop, - isHorizontalWritingMode() ? offsetTop : LayoutUnit()); - - boundingBox.moveBy(logicalOffsetFromTop); - - LayoutUnit logicalTopForRenderer = region->logicalTopOfFlowThreadContentRect(boundingBox); - LayoutUnit logicalBottomForRenderer = region->logicalBottomOfFlowThreadContentRect(boundingBox); - - // if the bounding box of the current element doesn't intersect the region box - // close the current range only if the start element began inside the region, - // otherwise just move the start position after this node and keep skipping them until we found a proper start position. - if (!boxIntersectsRegion(logicalTopForRenderer, logicalBottomForRenderer, logicalTopForRegion, logicalBottomForRegion)) { - if (foundStartPosition) { - if (!startsAboveRegion) { - if (range->intersectsNode(node, IGNORE_EXCEPTION)) - range->setEndBefore(node, IGNORE_EXCEPTION); - rangeObjects.append(range->cloneRange(IGNORE_EXCEPTION)); - range = Range::create(contentNode->document()); - startsAboveRegion = true; - } else { - skipOverOutsideNodes = true; - } - } - if (skipOverOutsideNodes) - range->setStartAfter(node, IGNORE_EXCEPTION); - foundStartPosition = false; - continue; - } - - // start position - if (logicalTopForRenderer < logicalTopForRegion && startsAboveRegion) { - if (renderer->isText()) { // Text crosses region top - // for Text elements, just find the last textbox that is contained inside the region and use its start() offset as start position - RenderText* textRenderer = toRenderText(renderer); - for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { - if (offsetTop + box->logicalBottom() < logicalTopForRegion) - continue; - range->setStart(Position(toText(node), box->start())); - startsAboveRegion = false; - break; - } - } else { // node crosses region top - // for all elements, except Text, just set the start position to be before their children - startsAboveRegion = true; - range->setStart(Position(node, Position::PositionIsBeforeChildren)); - } - } else { // node starts inside region - // for elements that start inside the region, set the start position to be before them. If we found one, we will just skip the others until - // the range is closed. - if (startsAboveRegion) { - startsAboveRegion = false; - range->setStartBefore(node, IGNORE_EXCEPTION); - } - } - skipOverOutsideNodes = false; - foundStartPosition = true; - - // end position - if (logicalBottomForRegion < logicalBottomForRenderer && (endsBelowRegion || (!endsBelowRegion && !node->isDescendantOf(lastEndNode)))) { - // for Text elements, just find just find the last textbox that is contained inside the region and use its start()+len() offset as end position - if (renderer->isText()) { // Text crosses region bottom - RenderText* textRenderer = toRenderText(renderer); - InlineTextBox* lastBox = 0; - for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { - if ((offsetTop + box->logicalTop()) < logicalBottomForRegion) { - lastBox = box; - continue; - } - ASSERT(lastBox); - if (lastBox) - range->setEnd(Position(toText(node), lastBox->start() + lastBox->len())); - break; - } - endsBelowRegion = false; - lastEndNode = node; - } else { // node crosses region bottom - // for all elements, except Text, just set the start position to be after their children - range->setEnd(Position(node, Position::PositionIsAfterChildren)); - endsBelowRegion = true; - lastEndNode = node; - } - } else { // node ends inside region - // for elements that ends inside the region, set the end position to be after them - // allow this end position to be changed only by other elements that are not descendants of the current end node - if (endsBelowRegion || (!endsBelowRegion && !node->isDescendantOf(lastEndNode))) { - range->setEndAfter(node, IGNORE_EXCEPTION); - endsBelowRegion = false; - lastEndNode = node; - } - } - } - if (foundStartPosition || skipOverOutsideNodes) - rangeObjects.append(range); - } -} - -} diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderNamedFlowThread.h b/chromium/third_party/WebKit/Source/core/rendering/RenderNamedFlowThread.h deleted file mode 100644 index 6528c1106c5..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderNamedFlowThread.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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 "core/rendering/RenderFlowThread.h" -#include "platform/Timer.h" -#include "wtf/HashCountedSet.h" -#include "wtf/ListHashSet.h" -#include "wtf/text/AtomicString.h" - -namespace WebCore { - -class NamedFlow; -class Node; -class RenderNamedFlowThread; - -typedef ListHashSet<RenderNamedFlowThread*> RenderNamedFlowThreadList; -typedef HashCountedSet<RenderNamedFlowThread*> RenderNamedFlowThreadCountedSet; -typedef ListHashSet<Node*> NamedFlowContentNodes; - -class RenderNamedFlowThread FINAL : public RenderFlowThread { -public: - virtual ~RenderNamedFlowThread(); - - static RenderNamedFlowThread* createAnonymous(Document*, PassRefPtr<NamedFlow>); - - const AtomicString& flowThreadName() const; - - const RenderRegionList& invalidRenderRegionList() const { return m_invalidRegionList; } - - RenderObject* nextRendererForNode(Node*) const; - RenderObject* previousRendererForNode(Node*) const; - - void addFlowChild(RenderObject* newChild); - 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; - - virtual void regionChangedWritingMode(RenderRegion*) OVERRIDE; - - bool overset() const { return m_overset; } - void computeOversetStateForRegions(LayoutUnit oldClientAfterEdge); - - 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); } - bool isMarkedForDestruction() const; - void getRanges(Vector<RefPtr<Range> >&, const RenderRegion*) const; - -protected: - void setMarkForDestruction(); - void resetMarkForDestruction(); - -private: - RenderNamedFlowThread(PassRefPtr<NamedFlow>); - - virtual const char* renderName() const OVERRIDE; - virtual bool isRenderNamedFlowThread() const OVERRIDE { return true; } - virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; - - virtual void dispatchRegionLayoutUpdateEvent() OVERRIDE; - virtual void dispatchRegionOversetChangeEvent() OVERRIDE; - - bool dependsOn(RenderNamedFlowThread* otherRenderFlowThread) const; - void addDependencyOnFlowThread(RenderNamedFlowThread*); - void removeDependencyOnFlowThread(RenderNamedFlowThread*); - - void addRegionToNamedFlowThread(RenderRegion*); - - void checkInvalidRegions(); - - bool canBeDestroyed() const { return m_invalidRegionList.isEmpty() && m_regionList.isEmpty() && m_contentNodes.isEmpty(); } - void regionLayoutUpdateEventTimerFired(Timer<RenderNamedFlowThread>*); - void regionOversetChangeEventTimerFired(Timer<RenderNamedFlowThread>*); - void clearContentNodes(); - void updateWritingMode(); - -private: - // 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; - - RenderRegionList m_invalidRegionList; - - bool m_overset : 1; - - // The DOM Object that represents a named flow. - RefPtr<NamedFlow> m_namedFlow; - - Timer<RenderNamedFlowThread> m_regionLayoutUpdateEventTimer; - Timer<RenderNamedFlowThread> m_regionOversetChangeEventTimer; -}; - -DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderNamedFlowThread, isRenderNamedFlowThread()); - -} // namespace WebCore - -#endif // RenderNamedFlowThread_h - diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderObject.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderObject.cpp index 1192be3d768..90af71bf364 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderObject.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderObject.cpp @@ -27,48 +27,43 @@ #include "config.h" #include "core/rendering/RenderObject.h" -#include "HTMLNames.h" -#include "RuntimeEnabledFeatures.h" +#include "core/HTMLNames.h" #include "core/accessibility/AXObjectCache.h" #include "core/animation/ActiveAnimations.h" #include "core/css/resolver/StyleResolver.h" +#include "core/dom/ElementTraversal.h" +#include "core/dom/shadow/ShadowRoot.h" #include "core/editing/EditingBoundary.h" #include "core/editing/FrameSelection.h" #include "core/editing/htmlediting.h" +#include "core/fetch/ResourceLoadPriorityOptimizer.h" #include "core/fetch/ResourceLoader.h" +#include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/html/HTMLAnchorElement.h" #include "core/html/HTMLElement.h" #include "core/html/HTMLHtmlElement.h" +#include "core/html/HTMLTableCellElement.h" #include "core/html/HTMLTableElement.h" #include "core/page/AutoscrollController.h" #include "core/page/EventHandler.h" -#include "core/frame/Frame.h" -#include "core/frame/FrameView.h" #include "core/page/Page.h" #include "core/frame/Settings.h" #include "core/frame/UseCounter.h" -#include "core/frame/animation/AnimationController.h" -#include "core/rendering/CompositedLayerMapping.h" #include "core/rendering/FlowThreadController.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/RenderCounter.h" #include "core/rendering/RenderDeprecatedFlexibleBox.h" #include "core/rendering/RenderFlexibleBox.h" +#include "core/rendering/RenderFlowThread.h" #include "core/rendering/RenderGeometryMap.h" #include "core/rendering/RenderGrid.h" #include "core/rendering/RenderImage.h" #include "core/rendering/RenderImageResourceStyleImage.h" #include "core/rendering/RenderInline.h" #include "core/rendering/RenderLayer.h" -#include "core/rendering/RenderLayerCompositor.h" #include "core/rendering/RenderListItem.h" #include "core/rendering/RenderMarquee.h" -#include "core/rendering/RenderMultiColumnBlock.h" -#include "core/rendering/RenderNamedFlowThread.h" -#include "core/rendering/RenderRegion.h" -#include "core/rendering/RenderRuby.h" -#include "core/rendering/RenderRubyText.h" #include "core/rendering/RenderScrollbarPart.h" #include "core/rendering/RenderTableCaption.h" #include "core/rendering/RenderTableCell.h" @@ -76,15 +71,20 @@ #include "core/rendering/RenderTableRow.h" #include "core/rendering/RenderTheme.h" #include "core/rendering/RenderView.h" +#include "core/rendering/compositing/CompositedLayerMapping.h" +#include "core/rendering/compositing/RenderLayerCompositor.h" #include "core/rendering/style/ContentData.h" -#include "core/rendering/style/CursorList.h" #include "core/rendering/style/ShadowList.h" -#include "core/rendering/svg/SVGRenderSupport.h" +#include "platform/JSONValues.h" #include "platform/Partitions.h" +#include "platform/RuntimeEnabledFeatures.h" +#include "platform/TraceEvent.h" +#include "platform/TracedValue.h" #include "platform/geometry/TransformState.h" #include "platform/graphics/GraphicsContext.h" #include "wtf/RefCountedLeakCounter.h" #include "wtf/text/StringBuilder.h" +#include "wtf/text/WTFString.h" #include <algorithm> #ifndef NDEBUG #include <stdio.h> @@ -94,20 +94,26 @@ using namespace std; namespace WebCore { +namespace { + +static bool gModifyRenderTreeStructureAnyState = false; + +} // namespace + using namespace HTMLNames; #ifndef NDEBUG -RenderObject::SetLayoutNeededForbiddenScope::SetLayoutNeededForbiddenScope(RenderObject* renderObject) +RenderObject::SetLayoutNeededForbiddenScope::SetLayoutNeededForbiddenScope(RenderObject& renderObject) : m_renderObject(renderObject) - , m_preexistingForbidden(m_renderObject->isSetNeedsLayoutForbidden()) + , m_preexistingForbidden(m_renderObject.isSetNeedsLayoutForbidden()) { - m_renderObject->setNeedsLayoutIsForbidden(true); + m_renderObject.setNeedsLayoutIsForbidden(true); } RenderObject::SetLayoutNeededForbiddenScope::~SetLayoutNeededForbiddenScope() { - m_renderObject->setNeedsLayoutIsForbidden(m_preexistingForbidden); + m_renderObject.setNeedsLayoutIsForbidden(m_preexistingForbidden); } #endif @@ -119,7 +125,8 @@ struct SameSizeAsRenderObject { #endif unsigned m_bitfields; unsigned m_bitfields2; - LayoutRect rects[2]; // Stores the old/new repaint rects. + LayoutRect rect; // Stores the previous paint invalidation rect. + LayoutPoint position; // Stores the previous position from the paint invalidation container. }; COMPILE_ASSERT(sizeof(RenderObject) == sizeof(SameSizeAsRenderObject), RenderObject_should_stay_small); @@ -140,7 +147,7 @@ void RenderObject::operator delete(void* ptr) RenderObject* RenderObject::createObject(Element* element, RenderStyle* style) { - Document& doc = element->document(); + ASSERT(isAllowedToModifyRenderTreeStructure(element->document())); // Minimal support for content properties replacing an entire element. // Works only if we have exactly one piece of content and it's a URL. @@ -157,20 +164,10 @@ RenderObject* RenderObject::createObject(Element* element, RenderStyle* style) image->setIsGeneratedContent(); } else image->setImageResource(RenderImageResource::create()); - image->setStyleInternal(0); + image->setStyleInternal(nullptr); return image; } - if (element->hasTagName(rubyTag)) { - if (style->display() == INLINE) - return new RenderRubyAsInline(element); - else if (style->display() == BLOCK) - return new RenderRubyAsBlock(element); - } - // treat <rt> as ruby text ONLY if it still has its default treatment of block - if (element->hasTagName(rtTag) && style->display() == BLOCK) - return new RenderRubyText(element); - switch (style->display()) { case NONE: return 0; @@ -178,8 +175,6 @@ RenderObject* RenderObject::createObject(Element* element, RenderStyle* style) return new RenderInline(element); case BLOCK: case INLINE_BLOCK: - if ((!style->hasAutoColumnCount() || !style->hasAutoColumnWidth()) && doc.regionBasedColumnsEnabled()) - return new RenderMultiColumnBlock(element); return new RenderBlockFlow(element); case LIST_ITEM: return new RenderListItem(element); @@ -217,7 +212,7 @@ DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, renderObjectCounter, ("Rend RenderObject::RenderObject(Node* node) : ImageResourceClient() - , m_style(0) + , m_style(nullptr) , m_node(node) , m_parent(0) , m_previous(0) @@ -235,6 +230,7 @@ RenderObject::RenderObject(Node* node) RenderObject::~RenderObject() { + ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->removeRenderObject(this); #ifndef NDEBUG ASSERT(!m_hasAXObject); renderObjectCounter.decrement(); @@ -263,31 +259,24 @@ bool RenderObject::isDescendantOf(const RenderObject* obj) const return false; } -bool RenderObject::isBody() const -{ - return node() && node()->hasTagName(bodyTag); -} - bool RenderObject::isHR() const { - return node() && node()->hasTagName(hrTag); + return isHTMLHRElement(node()); } bool RenderObject::isLegend() const { - return node() && node()->hasTagName(legendTag); + return isHTMLLegendElement(node()); } void RenderObject::setFlowThreadStateIncludingDescendants(FlowThreadState state) { - setFlowThreadState(state); - - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - // If the child is a fragmentation context it already updated the descendants flag accordingly. - if (child->isRenderFlowThread()) + for (RenderObject *object = this; object; object = object->nextInPreOrder(this)) { + // If object is a fragmentation context it already updated the descendants flag accordingly. + if (object->isRenderFlowThread()) continue; - ASSERT(state != child->flowThreadState()); - child->setFlowThreadStateIncludingDescendants(state); + ASSERT(state != object->flowThreadState()); + object->setFlowThreadState(state); } } @@ -313,6 +302,8 @@ bool RenderObject::requiresAnonymousTableWrappers(const RenderObject* newChild) void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild) { + ASSERT(isAllowedToModifyRenderTreeStructure(document())); + RenderObjectChildList* children = virtualChildren(); ASSERT(children); if (!children) @@ -340,7 +331,7 @@ void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild) // 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: // <g display="none"><foreignObject><body style="position: relative">FOO... - // - requiresLayer() would return true for the <body>, creating a new RenderLayer + // - layerTypeRequired() would return true for the <body>, creating a new RenderLayer // - when the document is painted, both layers are painted. The <body> layer doesn't // know that it's inside a "hidden SVG subtree", and thus paints, even if it shouldn't. // To avoid the problem alltogether, detect early if we're inside a hidden SVG subtree @@ -351,6 +342,8 @@ void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild) void RenderObject::removeChild(RenderObject* oldChild) { + ASSERT(isAllowedToModifyRenderTreeStructure(document())); + RenderObjectChildList* children = virtualChildren(); ASSERT(children); if (!children) @@ -361,7 +354,7 @@ void RenderObject::removeChild(RenderObject* oldChild) RenderObject* RenderObject::nextInPreOrder() const { - if (RenderObject* o = firstChild()) + if (RenderObject* o = slowFirstChild()) return o; return nextInPreOrderAfterChildren(); @@ -383,7 +376,7 @@ RenderObject* RenderObject::nextInPreOrderAfterChildren() const RenderObject* RenderObject::nextInPreOrder(const RenderObject* stayWithin) const { - if (RenderObject* o = firstChild()) + if (RenderObject* o = slowFirstChild()) return o; return nextInPreOrderAfterChildren(stayWithin); @@ -407,8 +400,8 @@ RenderObject* RenderObject::nextInPreOrderAfterChildren(const RenderObject* stay RenderObject* RenderObject::previousInPreOrder() const { if (RenderObject* o = previousSibling()) { - while (o->lastChild()) - o = o->lastChild(); + while (RenderObject* lastChild = o->slowLastChild()) + o = lastChild; return o; } @@ -425,7 +418,7 @@ RenderObject* RenderObject::previousInPreOrder(const RenderObject* stayWithin) c RenderObject* RenderObject::childAt(unsigned index) const { - RenderObject* child = firstChild(); + RenderObject* child = slowFirstChild(); for (unsigned i = 0; child && i < index; i++) child = child->nextSibling(); return child; @@ -433,10 +426,10 @@ RenderObject* RenderObject::childAt(unsigned index) const RenderObject* RenderObject::lastLeafChild() const { - RenderObject* r = lastChild(); + RenderObject* r = slowLastChild(); while (r) { RenderObject* n = 0; - n = r->lastChild(); + n = r->slowLastChild(); if (!n) break; r = n; @@ -459,7 +452,7 @@ static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject* return; } - for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling()) + for (RenderObject* curr = obj->slowFirstChild(); curr; curr = curr->nextSibling()) addLayers(curr, parentLayer, newObject, beforeChild); } @@ -483,7 +476,7 @@ void RenderObject::removeLayers(RenderLayer* parentLayer) return; } - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) + for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling()) curr->removeLayers(parentLayer); } @@ -501,7 +494,7 @@ void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent) return; } - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) + for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling()) curr->moveLayers(oldParent, newParent); } @@ -520,7 +513,7 @@ RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject* // Step 2: If we don't have a layer, or our layer is the desired parent, then descend // into our siblings trying to find the next layer whose parent is the desired parent. if (!ourLayer || ourLayer == parentLayer) { - for (RenderObject* curr = startPoint ? startPoint->nextSibling() : firstChild(); + for (RenderObject* curr = startPoint ? startPoint->nextSibling() : slowFirstChild(); curr; curr = curr->nextSibling()) { RenderLayer* nextLayer = curr->findNextLayer(parentLayer, 0, false); if (nextLayer) @@ -543,13 +536,13 @@ RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject* RenderLayer* RenderObject::enclosingLayer() const { - const RenderObject* curr = this; - while (curr) { - RenderLayer* layer = curr->hasLayer() ? toRenderLayerModelObject(curr)->layer() : 0; - if (layer) - return layer; - curr = curr->parent(); + for (const RenderObject* current = this; current; current = current->parent()) { + if (current->hasLayer()) + return toRenderLayerModelObject(current)->layer(); } + // FIXME: We should remove the one caller that triggers this case and make + // this function return a reference. + ASSERT(!m_parent && !isRenderView()); return 0; } @@ -622,15 +615,6 @@ RenderFlowThread* RenderObject::locateFlowThreadContainingBlock() const return 0; } -RenderNamedFlowThread* RenderObject::renderNamedFlowThreadWrapper() const -{ - RenderObject* object = const_cast<RenderObject*>(this); - while (object && object->isAnonymousBlock() && !object->isRenderNamedFlowThread()) - object = object->parent(); - - return object && object->isRenderNamedFlowThread() ? toRenderNamedFlowThread(object) : 0; -} - RenderBlock* RenderObject::firstLineBlock() const { return 0; @@ -729,19 +713,12 @@ void RenderObject::checkBlockPositionedObjectsNeedLayout() if (isRenderBlock()) toRenderBlock(this)->checkPositionedObjectsNeedLayout(); } - -void RenderObject::checkNotInPartialLayout() -{ - // During partial layout, setNeedsLayout(true or false) should not be called. - ASSERT(!frameView()->partialLayout().isStopping()); -} #endif void RenderObject::setPreferredLogicalWidthsDirty(MarkingBehavior markParents) { - bool alreadyDirty = preferredLogicalWidthsDirty(); m_bitfields.setPreferredLogicalWidthsDirty(true); - if (!alreadyDirty && markParents == MarkContainingBlockChain && (isText() || !style()->hasOutOfFlowPosition())) + if (markParents == MarkContainingBlockChain && (isText() || !style()->hasOutOfFlowPosition())) invalidateContainerPreferredLogicalWidths(); } @@ -771,28 +748,22 @@ void RenderObject::invalidateContainerPreferredLogicalWidths() } } -void RenderObject::setLayerNeedsFullRepaint() -{ - ASSERT(hasLayer()); - toRenderLayerModelObject(this)->layer()->repainter().setRepaintStatus(NeedsFullRepaint); -} - -void RenderObject::setLayerNeedsFullRepaintForPositionedMovementLayout() +void RenderObject::setLayerNeedsFullPaintInvalidationForPositionedMovementLayout() { ASSERT(hasLayer()); toRenderLayerModelObject(this)->layer()->repainter().setRepaintStatus(NeedsFullRepaintForPositionedMovementLayout); } -RenderBlock* RenderObject::containerForFixedPosition(const RenderLayerModelObject* repaintContainer, bool* repaintContainerSkipped) const +RenderBlock* RenderObject::containerForFixedPosition(const RenderLayerModelObject* paintInvalidationContainer, bool* paintInvalidationContainerSkipped) const { - ASSERT(!repaintContainerSkipped || !*repaintContainerSkipped); + ASSERT(!paintInvalidationContainerSkipped || !*paintInvalidationContainerSkipped); ASSERT(!isText()); ASSERT(style()->position() == FixedPosition); RenderObject* ancestor = parent(); for (; ancestor && !ancestor->canContainFixedPositionObjects(); ancestor = ancestor->parent()) { - if (repaintContainerSkipped && ancestor == repaintContainer) - *repaintContainerSkipped = true; + if (paintInvalidationContainerSkipped && ancestor == paintInvalidationContainer) + *paintInvalidationContainerSkipped = true; } ASSERT(!ancestor || !ancestor->isAnonymousBlock()); @@ -816,7 +787,7 @@ RenderBlock* RenderObject::containingBlock() const if (o->style()->position() != StaticPosition && (!o->isInline() || o->isReplaced())) break; - if (o->canContainAbsolutePositionObjects()) + if (o->canContainFixedPositionObjects()) break; if (o->style()->hasInFlowPosition() && o->isInline() && !o->isReplaced()) { @@ -827,6 +798,9 @@ RenderBlock* RenderObject::containingBlock() const o = o->parent(); } + if (o && !o->isRenderBlock()) + o = o->containingBlock(); + while (o && o->isAnonymousBlock()) o = o->containingBlock(); } else { @@ -840,29 +814,66 @@ RenderBlock* RenderObject::containingBlock() const return toRenderBlock(o); } -static bool mustRepaintFillLayers(const RenderObject* renderer, const FillLayer* layer) +RenderObject* RenderObject::clippingContainer() const +{ + RenderObject* container = const_cast<RenderObject*>(this); + while (container) { + if (container->style()->position() == FixedPosition) { + for (container = container->parent(); container && !container->canContainFixedPositionObjects(); container = container->parent()) { + // CSS clip applies to fixed position elements even for ancestors that are not what the + // fixed element is positioned with respect to. + if (container->hasClip()) + return container; + } + } else { + container = container->containingBlock(); + } + + if (!container) + return 0; + if (container->hasClipOrOverflowClip()) + return container; + } + return 0; +} + +bool RenderObject::canRenderBorderImage() const +{ + ASSERT(style()->hasBorder()); + + StyleImage* borderImage = style()->borderImage().image(); + return borderImage && borderImage->canRender(*this, style()->effectiveZoom()) && borderImage->isLoaded(); +} + +bool RenderObject::mustInvalidateFillLayersPaintOnWidthChange(const FillLayer& layer) const { // Nobody will use multiple layers without wanting fancy positioning. - if (layer->next()) + if (layer.next()) return true; // Make sure we have a valid image. - StyleImage* img = layer->image(); - if (!img || !img->canRender(renderer, renderer->style()->effectiveZoom())) + StyleImage* img = layer.image(); + if (!img || !img->canRender(*this, style()->effectiveZoom())) return false; - if (!layer->xPosition().isZero() || !layer->yPosition().isZero()) + if (layer.repeatX() != RepeatFill && layer.repeatX() != NoRepeatFill) return true; - EFillSizeType sizeType = layer->sizeType(); + if (layer.xPosition().isPercent() && !layer.xPosition().isZero()) + return true; + + if (layer.backgroundXOrigin() != LeftEdge) + return true; + + EFillSizeType sizeType = layer.sizeType(); if (sizeType == Contain || sizeType == Cover) return true; if (sizeType == SizeLength) { - if (layer->sizeLength().width().isPercent() || layer->sizeLength().height().isPercent()) + if (layer.sizeLength().width().isPercent() && !layer.sizeLength().width().isZero()) return true; - if (img->isGeneratedImage() && (layer->sizeLength().width().isAuto() || layer->sizeLength().height().isAuto())) + if (img->isGeneratedImage() && layer.sizeLength().width().isAuto()) return true; } else if (img->usesImageContainerSize()) { return true; @@ -871,28 +882,76 @@ static bool mustRepaintFillLayers(const RenderObject* renderer, const FillLayer* return false; } -bool RenderObject::borderImageIsLoadedAndCanBeRendered() const +bool RenderObject::mustInvalidateFillLayersPaintOnHeightChange(const FillLayer& layer) const { - ASSERT(style()->hasBorder()); + // Nobody will use multiple layers without wanting fancy positioning. + if (layer.next()) + return true; - StyleImage* borderImage = style()->borderImage().image(); - return borderImage && borderImage->canRender(this, style()->effectiveZoom()) && borderImage->isLoaded(); + // Make sure we have a valid image. + StyleImage* img = layer.image(); + if (!img || !img->canRender(*this, style()->effectiveZoom())) + return false; + + if (layer.repeatY() != RepeatFill && layer.repeatY() != NoRepeatFill) + return true; + + if (layer.yPosition().isPercent() && !layer.yPosition().isZero()) + return true; + + if (layer.backgroundYOrigin() != TopEdge) + return true; + + EFillSizeType sizeType = layer.sizeType(); + + if (sizeType == Contain || sizeType == Cover) + return true; + + if (sizeType == SizeLength) { + if (layer.sizeLength().height().isPercent() && !layer.sizeLength().height().isZero()) + return true; + if (img->isGeneratedImage() && layer.sizeLength().height().isAuto()) + return true; + } else if (img->usesImageContainerSize()) { + return true; + } + + return false; } -bool RenderObject::mustRepaintBackgroundOrBorder() const +bool RenderObject::mustInvalidateBackgroundOrBorderPaintOnWidthChange() const { - if (hasMask() && mustRepaintFillLayers(this, style()->maskLayers())) + if (hasMask() && mustInvalidateFillLayersPaintOnWidthChange(*style()->maskLayers())) return true; // If we don't have a background/border/mask, then nothing to do. if (!hasBoxDecorations()) return false; - if (mustRepaintFillLayers(this, style()->backgroundLayers())) + if (mustInvalidateFillLayersPaintOnWidthChange(*style()->backgroundLayers())) + return true; + + // Our fill layers are ok. Let's check border. + if (style()->hasBorder() && canRenderBorderImage()) + return true; + + return false; +} + +bool RenderObject::mustInvalidateBackgroundOrBorderPaintOnHeightChange() const +{ + if (hasMask() && mustInvalidateFillLayersPaintOnHeightChange(*style()->maskLayers())) + return true; + + // If we don't have a background/border/mask, then nothing to do. + if (!hasBoxDecorations()) + return false; + + if (mustInvalidateFillLayersPaintOnHeightChange(*style()->backgroundLayers())) return true; // Our fill layers are ok. Let's check border. - if (style()->hasBorder() && borderImageIsLoadedAndCanBeRendered()) + if (style()->hasBorder() && canRenderBorderImage()) return true; return false; @@ -1250,22 +1309,62 @@ void RenderObject::paintOutline(PaintInfo& paintInfo, const LayoutRect& paintRec graphicsContext->endLayer(); } -IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms) const +void RenderObject::addChildFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer) { - if (useTransforms) { - Vector<FloatQuad> quads; - absoluteQuads(quads); - - size_t n = quads.size(); - if (!n) - return IntRect(); + for (RenderObject* current = slowFirstChild(); current; current = current->nextSibling()) { + if (current->isText() || current->isListMarker()) + continue; - IntRect result = quads[0].enclosingBoundingBox(); - for (size_t i = 1; i < n; ++i) - result.unite(quads[i].enclosingBoundingBox()); - return result; + if (current->isBox()) { + RenderBox* box = toRenderBox(current); + if (box->hasLayer()) { + Vector<IntRect> layerFocusRingRects; + box->addFocusRingRects(layerFocusRingRects, LayoutPoint(), box); + for (size_t i = 0; i < layerFocusRingRects.size(); ++i) { + FloatQuad quadInBox = box->localToContainerQuad(FloatRect(layerFocusRingRects[i]), paintContainer); + rects.append(pixelSnappedIntRect(LayoutRect(quadInBox.boundingBox()))); + } + } else { + FloatPoint pos(additionalOffset); + pos.move(box->locationOffset()); // FIXME: Snap offsets? crbug.com/350474 + box->addFocusRingRects(rects, flooredIntPoint(pos), paintContainer); + } + } else { + current->addFocusRingRects(rects, additionalOffset, paintContainer); + } } +} + +// FIXME: In repaint-after-layout, we should be able to change the logic to remove the need for this function. See crbug.com/368416. +LayoutPoint RenderObject::positionFromPaintInvalidationContainer(const RenderLayerModelObject* paintInvalidationContainer) const +{ + // FIXME: This assert should be re-enabled when we move paint invalidation to after compositing update. crbug.com/360286 + // ASSERT(containerForPaintInvalidation() == paintInvalidationContainer); + + LayoutPoint offset = isBox() ? toRenderBox(this)->location() : LayoutPoint(); + if (paintInvalidationContainer == this) + return offset; + + return roundedIntPoint(localToContainerPoint(offset, paintInvalidationContainer)); +} + +IntRect RenderObject::absoluteBoundingBoxRect() const +{ + Vector<FloatQuad> quads; + absoluteQuads(quads); + size_t n = quads.size(); + if (!n) + return IntRect(); + + IntRect result = quads[0].enclosingBoundingBox(); + for (size_t i = 1; i < n; ++i) + result.unite(quads[i].enclosingBoundingBox()); + return result; +} + +IntRect RenderObject::absoluteBoundingBoxRectIgnoringTransforms() const +{ FloatPoint absPos = localToAbsolute(); Vector<IntRect> rects; absoluteRects(rects, flooredLayoutPoint(absPos)); @@ -1283,18 +1382,11 @@ IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms) const void RenderObject::absoluteFocusRingQuads(Vector<FloatQuad>& quads) { Vector<IntRect> rects; - // FIXME: addFocusRingRects() needs to be passed this transform-unaware - // localToAbsolute() offset here because RenderInline::addFocusRingRects() - // implicitly assumes that. This doesn't work correctly with transformed - // descendants. - FloatPoint absolutePoint = localToAbsolute(); - addFocusRingRects(rects, flooredLayoutPoint(absolutePoint)); + const RenderLayerModelObject* container = containerForPaintInvalidation(); + addFocusRingRects(rects, LayoutPoint(localToContainerPoint(FloatPoint(), container)), container); size_t count = rects.size(); - for (size_t i = 0; i < count; ++i) { - IntRect rect = rects[i]; - rect.move(-absolutePoint.x(), -absolutePoint.y()); - quads.append(localToAbsoluteQuad(FloatQuad(rect))); - } + for (size_t i = 0; i < count; ++i) + quads.append(container->localToAbsoluteQuad(FloatQuad(rects[i]))); } FloatRect RenderObject::absoluteBoundingBoxRectForRange(const Range* range) @@ -1317,16 +1409,16 @@ FloatRect RenderObject::absoluteBoundingBoxRectForRange(const Range* range) void RenderObject::addAbsoluteRectForLayer(LayoutRect& result) { if (hasLayer()) - result.unite(absoluteBoundingBoxRectIgnoringTransforms()); - for (RenderObject* current = firstChild(); current; current = current->nextSibling()) + result.unite(absoluteBoundingBoxRect()); + for (RenderObject* current = slowFirstChild(); current; current = current->nextSibling()) current->addAbsoluteRectForLayer(result); } LayoutRect RenderObject::paintingRootRect(LayoutRect& topLevelRect) { - LayoutRect result = absoluteBoundingBoxRectIgnoringTransforms(); + LayoutRect result = absoluteBoundingBoxRect(); topLevelRect = result; - for (RenderObject* current = firstChild(); current; current = current->nextSibling()) + for (RenderObject* current = slowFirstChild(); current; current = current->nextSibling()) current->addAbsoluteRectForLayer(result); return result; } @@ -1335,145 +1427,157 @@ void RenderObject::paint(PaintInfo&, const LayoutPoint&) { } -RenderLayerModelObject* RenderObject::containerForRepaint() const +const RenderLayerModelObject* RenderObject::containerForPaintInvalidation() const { - RenderView* v = view(); - if (!v) + if (!isRooted()) return 0; - RenderLayerModelObject* repaintContainer = 0; + return adjustCompositedContainerForSpecialAncestors(enclosingCompositedContainer()); +} - if (v->usesCompositing()) { - if (RenderLayer* parentLayer = enclosingLayer()) { - RenderLayer* compLayer = parentLayer->enclosingCompositingLayerForRepaint(); - if (compLayer) - repaintContainer = compLayer->renderer(); - } +const RenderLayerModelObject* RenderObject::enclosingCompositedContainer() const +{ + RenderLayerModelObject* container = 0; + if (view()->usesCompositing()) { + // FIXME: CompositingState is not necessarily up to date for many callers of this function. + DisableCompositingQueryAsserts disabler; + + if (RenderLayer* compositingLayer = enclosingLayer()->enclosingCompositingLayerForRepaint()) + container = compositingLayer->renderer(); } + return container; +} + +const RenderLayerModelObject* RenderObject::adjustCompositedContainerForSpecialAncestors(const RenderLayerModelObject* paintInvalidationContainer) const +{ if (document().view()->hasSoftwareFilters()) { - if (RenderLayer* parentLayer = enclosingLayer()) { - RenderLayer* enclosingFilterLayer = parentLayer->enclosingFilterLayer(); - if (enclosingFilterLayer) - return enclosingFilterLayer->renderer(); - } + if (RenderLayer* enclosingFilterLayer = enclosingLayer()->enclosingFilterLayer()) + return enclosingFilterLayer->renderer(); } - // 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 - // repainting to do individual region repaints. - RenderFlowThread* parentRenderFlowThread = flowThreadContainingBlock(); - if (parentRenderFlowThread) { - // The ancestor document will do the reparenting when the repaint propagates further up. - // We're just a seamless child document, and we don't need to do the hacking. - if (parentRenderFlowThread->document() != document()) - return repaintContainer; - // If we have already found a repaint container then we will repaint into that container only if it is part of the same - // flow thread. Otherwise we will need to catch the repaint call and send it to the flow thread. - RenderFlowThread* repaintContainerFlowThread = repaintContainer ? repaintContainer->flowThreadContainingBlock() : 0; - if (!repaintContainerFlowThread || repaintContainerFlowThread != parentRenderFlowThread) - repaintContainer = parentRenderFlowThread; + // If we have a flow thread, then we need to do individual paint invalidations within the RenderRegions instead. + // Return the flow thread as a paint invalidation container in order to create a chokepoint that allows us to change + // paint invalidation to do individual region paint invalidations. + if (RenderFlowThread* parentRenderFlowThread = flowThreadContainingBlock()) { + // If we have already found a paint invalidation container then we will invalidate paints in that container only if it is part of the same + // flow thread. Otherwise we will need to catch the paint invalidation call and send it to the flow thread. + if (!paintInvalidationContainer || paintInvalidationContainer->flowThreadContainingBlock() != parentRenderFlowThread) + paintInvalidationContainer = parentRenderFlowThread; } - return repaintContainer; + return paintInvalidationContainer ? paintInvalidationContainer : view(); } -void RenderObject::repaintUsingContainer(const RenderLayerModelObject* repaintContainer, const IntRect& r) const +bool RenderObject::isPaintInvalidationContainer() const { - if (!repaintContainer) { - view()->repaintViewRectangle(r); - return; - } + return hasLayer() && toRenderLayerModelObject(this)->layer()->isRepaintContainer(); +} - if (repaintContainer->compositingState() == PaintsIntoGroupedBacking) { - ASSERT(repaintContainer->groupedMapping()); +template<typename T> PassRefPtr<JSONValue> jsonObjectForRect(const T& rect) +{ + RefPtr<JSONObject> object = JSONObject::create(); + object->setNumber("x", rect.x()); + object->setNumber("y", rect.y()); + object->setNumber("width", rect.width()); + object->setNumber("height", rect.height()); + return object.release(); +} - // Not clean, but if squashing layer does not yet exist here (e.g. repaint invalidation coming from within recomputing compositing requirements) - // then it's ok to just exit here, since the squashing layer will get repainted when it is newly created. - if (!repaintContainer->groupedMapping()->squashingLayer()) - return; +static PassRefPtr<JSONValue> jsonObjectForPaintInvalidationInfo(const IntRect& rect, const String& invalidationReason) +{ + RefPtr<JSONObject> object = JSONObject::create(); + object->setValue("rect", jsonObjectForRect(rect)); + object->setString("invalidation_reason", invalidationReason); + return object.release(); +} +LayoutRect RenderObject::computePaintInvalidationRect(const RenderLayerModelObject* paintInvalidationContainer) const +{ + return clippedOverflowRectForPaintInvalidation(paintInvalidationContainer); +} - IntRect offsetRect(r); +void RenderObject::invalidatePaintUsingContainer(const RenderLayerModelObject* paintInvalidationContainer, const IntRect& r, InvalidationReason invalidationReason) const +{ + if (r.isEmpty()) + return; - // First, convert the repaint rect into the space of the repaintContainer - TransformState transformState(TransformState::ApplyTransformDirection, FloatQuad(FloatRect(r))); - mapLocalToContainer(repaintContainer, transformState, ApplyContainerFlip); - transformState.flatten(); - offsetRect = transformState.lastPlanarQuad().enclosingBoundingBox(); + // FIXME: This should be an assert, but editing/selection can trigger this case to invalidate + // the selection. crbug.com/368140. + if (!isRooted()) + return; - // FIXME: the repaint rect computed below could be tighter in uncommon nested transform cases, if we passed the quad - // directly to the next chunk of code. + TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"), "RenderObject::invalidatePaintUsingContainer()", + "object", this->debugName().ascii(), + "info", TracedValue::fromJSONValue(jsonObjectForPaintInvalidationInfo(r, invalidationReasonToString(invalidationReason)))); - // Then, convert the repaint rect from repaintConainer space into the squashing GraphicsLayer's coordinates. - if (repaintContainer->hasTransform()) - offsetRect = repaintContainer->layer()->transform()->mapRect(r); - offsetRect.move(-repaintContainer->layer()->offsetFromSquashingLayerOrigin()); - repaintContainer->groupedMapping()->squashingLayer()->setNeedsDisplayInRect(offsetRect); - return; - } + // For querying RenderLayer::compositingState() + DisableCompositingQueryAsserts disabler; - if (repaintContainer->isRenderFlowThread()) { - toRenderFlowThread(repaintContainer)->repaintRectangleInRegions(r); + if (paintInvalidationContainer->isRenderFlowThread()) { + toRenderFlowThread(paintInvalidationContainer)->repaintRectangleInRegions(r); return; } - if (repaintContainer->hasFilter() && repaintContainer->layer()->requiresFullLayerImageForFilters()) { - repaintContainer->layer()->repainter().setFilterBackendNeedsRepaintingInRect(r); + if (paintInvalidationContainer->hasFilter() && paintInvalidationContainer->layer()->requiresFullLayerImageForFilters()) { + paintInvalidationContainer->layer()->repainter().setFilterBackendNeedsRepaintingInRect(r); return; } RenderView* v = view(); - if (repaintContainer->isRenderView()) { - ASSERT(repaintContainer == v); - bool viewHasCompositedLayer = v->hasLayer() && v->layer()->compositingState() == PaintsIntoOwnBacking; - if (!viewHasCompositedLayer) { - IntRect repaintRectangle = r; - if (viewHasCompositedLayer && v->layer()->transform()) - repaintRectangle = v->layer()->transform()->mapRect(r); - v->repaintViewRectangle(repaintRectangle); - return; - } + if (paintInvalidationContainer->isRenderView()) { + ASSERT(paintInvalidationContainer == v); + v->repaintViewRectangle(r); + return; } if (v->usesCompositing()) { - ASSERT(repaintContainer->hasLayer() && repaintContainer->layer()->compositingState() == PaintsIntoOwnBacking); - repaintContainer->layer()->repainter().setBackingNeedsRepaintInRect(r); + ASSERT(paintInvalidationContainer->hasLayer() && (paintInvalidationContainer->layer()->compositingState() == PaintsIntoOwnBacking || paintInvalidationContainer->layer()->compositingState() == PaintsIntoGroupedBacking)); + paintInvalidationContainer->layer()->repainter().setBackingNeedsRepaintInRect(r); } } -void RenderObject::repaint() const +void RenderObject::paintInvalidationForWholeRenderer() const { - // Don't repaint if we're unrooted (note that view() still returns the view when unrooted) - RenderView* view; - if (!isRooted(&view)) + if (!isRooted()) return; - if (view->document().printing()) - return; // Don't repaint if we're printing. + if (view()->document().printing()) + return; // Don't invalidate paints if we're printing. - RenderLayerModelObject* repaintContainer = containerForRepaint(); - repaintUsingContainer(repaintContainer ? repaintContainer : view, pixelSnappedIntRect(clippedOverflowRectForRepaint(repaintContainer))); + // FIXME: really, we're in the paint invalidation phase here, and the following queries are legal. + // Until those states are fully fledged, I'll just disable the ASSERTS. + DisableCompositingQueryAsserts disabler; + const RenderLayerModelObject* paintInvalidationContainer = containerForPaintInvalidation(); + LayoutRect paintInvalidationRect = boundsRectForPaintInvalidation(paintInvalidationContainer); + invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(paintInvalidationRect), InvalidationPaint); } -void RenderObject::repaintRectangle(const LayoutRect& r) const +LayoutRect RenderObject::boundsRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const { - // Don't repaint if we're unrooted (note that view() still returns the view when unrooted) - RenderView* view; - if (!isRooted(&view)) + if (!paintInvalidationContainer) + return computePaintInvalidationRect(paintInvalidationContainer); + return RenderLayer::computeRepaintRect(this, paintInvalidationContainer->layer()); +} + +void RenderObject::invalidatePaintRectangle(const LayoutRect& r) const +{ + if (!isRooted()) return; - if (view->document().printing()) - return; // Don't repaint if we're printing. + if (view()->document().printing()) + return; // Don't invalidate paints if we're printing. LayoutRect dirtyRect(r); - // FIXME: layoutDelta needs to be applied in parts before/after transforms and - // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 - dirtyRect.move(view->layoutDelta()); + if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) { + // FIXME: layoutDelta needs to be applied in parts before/after transforms and + // paint invalidation containers. https://bugs.webkit.org/show_bug.cgi?id=23308 + dirtyRect.move(view()->layoutDelta()); + } - RenderLayerModelObject* repaintContainer = containerForRepaint(); - computeRectForRepaint(repaintContainer, dirtyRect); - repaintUsingContainer(repaintContainer ? repaintContainer : view, pixelSnappedIntRect(dirtyRect)); + const RenderLayerModelObject* paintInvalidationContainer = containerForPaintInvalidation(); + RenderLayer::mapRectToRepaintBacking(this, paintInvalidationContainer, dirtyRect); + invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(dirtyRect), InvalidationPaintRectangle); } IntRect RenderObject::pixelSnappedAbsoluteClippedOverflowRect() const @@ -1481,84 +1585,165 @@ IntRect RenderObject::pixelSnappedAbsoluteClippedOverflowRect() const return pixelSnappedIntRect(absoluteClippedOverflowRect()); } -bool RenderObject::repaintAfterLayoutIfNeeded(const RenderLayerModelObject* repaintContainer, bool wasSelfLayout, - const LayoutRect& oldBounds, const LayoutRect& oldOutlineBox, - const LayoutRect* newBoundsPtr, const LayoutRect* newOutlineBoxRectPtr) +const char* RenderObject::invalidationReasonToString(InvalidationReason reason) const +{ + switch (reason) { + case InvalidationIncremental: + return "incremental"; + case InvalidationSelfLayout: + return "self layout"; + case InvalidationBorderFitLines: + return "border fit lines"; + case InvalidationBorderRadius: + return "border radius"; + case InvalidationBoundsChangeWithBackground: + return "bounds change with background"; + case InvalidationBoundsChange: + return "bounds change"; + case InvalidationLocationChange: + return "location change"; + case InvalidationScroll: + return "scroll"; + case InvalidationSelection: + return "selection"; + case InvalidationLayer: + return "layer"; + case InvalidationPaint: + return "invalidate paint"; + case InvalidationPaintRectangle: + return "invalidate paint rectangle"; + } + ASSERT_NOT_REACHED(); + return ""; +} + +void RenderObject::invalidateTreeAfterLayout(const RenderLayerModelObject& paintInvalidationContainer) +{ + // If we didn't need paint invalidation then our children don't need as well. + // Skip walking down the tree as everything should be fine below us. + if (!shouldCheckForPaintInvalidationAfterLayout()) + return; + + clearPaintInvalidationState(); + + for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling()) { + if (!child->isOutOfFlowPositioned()) + child->invalidateTreeAfterLayout(paintInvalidationContainer); + } +} + +static PassRefPtr<JSONValue> jsonObjectForOldAndNewRects(const LayoutRect& oldRect, const LayoutRect& newRect) +{ + RefPtr<JSONObject> object = JSONObject::create(); + + object->setValue("old", jsonObjectForRect(oldRect)); + object->setValue("new", jsonObjectForRect(newRect)); + return object.release(); +} + +bool RenderObject::invalidatePaintAfterLayoutIfNeeded(const RenderLayerModelObject* paintInvalidationContainer, bool wasSelfLayout, + const LayoutRect& oldBounds, const LayoutPoint& oldLocation, const LayoutRect* newBoundsPtr, const LayoutPoint* newLocationPtr) { RenderView* v = view(); if (v->document().printing()) - return false; // Don't repaint if we're printing. + return false; // Don't invalidate paints if we're printing. // This ASSERT fails due to animations. See https://bugs.webkit.org/show_bug.cgi?id=37048 - // ASSERT(!newBoundsPtr || *newBoundsPtr == clippedOverflowRectForRepaint(repaintContainer)); - LayoutRect newBounds = newBoundsPtr ? *newBoundsPtr : clippedOverflowRectForRepaint(repaintContainer); - LayoutRect newOutlineBox; + // ASSERT(!newBoundsPtr || *newBoundsPtr == clippedOverflowRectForPaintInvalidation(paintInvalidationContainer)); + LayoutRect newBounds = newBoundsPtr ? *newBoundsPtr : computePaintInvalidationRect(); + LayoutPoint newLocation = newLocationPtr ? (*newLocationPtr) : RenderLayer::positionFromPaintInvalidationContainer(this, paintInvalidationContainer); + + // FIXME: This should use a ConvertableToTraceFormat when they are available in Blink. + TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"), "RenderObject::invalidatePaintAfterLayoutIfNeeded()", + "object", this->debugName().ascii(), + "info", TracedValue::fromJSONValue(jsonObjectForOldAndNewRects(oldBounds, newBounds))); + + InvalidationReason invalidationReason = wasSelfLayout ? InvalidationSelfLayout : InvalidationIncremental; - bool fullRepaint = wasSelfLayout; // Presumably a background or a border exists if border-fit:lines was specified. - if (!fullRepaint && style()->borderFit() == BorderFitLines) - fullRepaint = true; - if (!fullRepaint && style()->hasBorderRadius()) { + if (invalidationReason == InvalidationIncremental && style()->borderFit() == BorderFitLines) + invalidationReason = InvalidationBorderFitLines; + + if (invalidationReason == InvalidationIncremental && style()->hasBorderRadius()) { // If a border-radius exists and width/height is smaller than - // radius width/height, we cannot use delta-repaint. - RoundedRect oldRoundedRect = style()->getRoundedBorderFor(oldBounds, v); - RoundedRect newRoundedRect = style()->getRoundedBorderFor(newBounds, v); - fullRepaint = oldRoundedRect.radii() != newRoundedRect.radii(); + // radius width/height, we cannot use delta-paint-invalidation. + RoundedRect oldRoundedRect = style()->getRoundedBorderFor(oldBounds); + RoundedRect newRoundedRect = style()->getRoundedBorderFor(newBounds); + if (oldRoundedRect.radii() != newRoundedRect.radii()) + invalidationReason = InvalidationBorderRadius; } - if (!fullRepaint) { - // This ASSERT fails due to animations. See https://bugs.webkit.org/show_bug.cgi?id=37048 - // ASSERT(!newOutlineBoxRectPtr || *newOutlineBoxRectPtr == outlineBoundsForRepaint(repaintContainer)); - newOutlineBox = newOutlineBoxRectPtr ? *newOutlineBoxRectPtr : outlineBoundsForRepaint(repaintContainer); - if (newOutlineBox.location() != oldOutlineBox.location() || (mustRepaintBackgroundOrBorder() && (newBounds != oldBounds || newOutlineBox != oldOutlineBox))) - fullRepaint = true; + + if (invalidationReason == InvalidationIncremental && compositingState() != PaintsIntoOwnBacking && newLocation != oldLocation) + invalidationReason = InvalidationLocationChange; + + // If the bounds are the same then we know that none of the statements below + // can match, so we can early out since we will not need to do any + // invalidation. + if (invalidationReason == InvalidationIncremental && oldBounds == newBounds) + return false; + + if (invalidationReason == InvalidationIncremental) { + if (oldBounds.width() != newBounds.width() && mustInvalidateBackgroundOrBorderPaintOnWidthChange()) + invalidationReason = InvalidationBoundsChangeWithBackground; + else if (oldBounds.height() != newBounds.height() && mustInvalidateBackgroundOrBorderPaintOnHeightChange()) + invalidationReason = InvalidationBoundsChangeWithBackground; } - if (!repaintContainer) - repaintContainer = v; + // If we shifted, we don't know the exact reason so we are conservative and trigger a full invalidation. Shifting could + // be caused by some layout property (left / top) or some in-flow renderer inserted / removed before us in the tree. + if (invalidationReason == InvalidationIncremental && newBounds.location() != oldBounds.location()) + invalidationReason = InvalidationBoundsChange; + + // If the size is zero on one of our bounds then we know we're going to have + // to do a full invalidation of either old bounds or new bounds. If we fall + // into the incremental invalidation we'll issue two invalidations instead + // of one. + if (invalidationReason == InvalidationIncremental && (oldBounds.size().isZero() || newBounds.size().isZero())) + invalidationReason = InvalidationBoundsChange; + + ASSERT(paintInvalidationContainer); - if (fullRepaint) { - repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds)); + if (invalidationReason != InvalidationIncremental) { + invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(oldBounds), invalidationReason); if (newBounds != oldBounds) - repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds)); + invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(newBounds), invalidationReason); return true; } - if (newBounds == oldBounds && newOutlineBox == oldOutlineBox) - return false; - LayoutUnit deltaLeft = newBounds.x() - oldBounds.x(); if (deltaLeft > 0) - repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds.x(), oldBounds.y(), deltaLeft, oldBounds.height())); + invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(oldBounds.x(), oldBounds.y(), deltaLeft, oldBounds.height()), invalidationReason); else if (deltaLeft < 0) - repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds.x(), newBounds.y(), -deltaLeft, newBounds.height())); + invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(newBounds.x(), newBounds.y(), -deltaLeft, newBounds.height()), invalidationReason); LayoutUnit deltaRight = newBounds.maxX() - oldBounds.maxX(); if (deltaRight > 0) - repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds.maxX(), newBounds.y(), deltaRight, newBounds.height())); + invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(oldBounds.maxX(), newBounds.y(), deltaRight, newBounds.height()), invalidationReason); else if (deltaRight < 0) - repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds.maxX(), oldBounds.y(), -deltaRight, oldBounds.height())); + invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(newBounds.maxX(), oldBounds.y(), -deltaRight, oldBounds.height()), invalidationReason); LayoutUnit deltaTop = newBounds.y() - oldBounds.y(); if (deltaTop > 0) - repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds.x(), oldBounds.y(), oldBounds.width(), deltaTop)); + invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(oldBounds.x(), oldBounds.y(), oldBounds.width(), deltaTop), invalidationReason); else if (deltaTop < 0) - repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds.x(), newBounds.y(), newBounds.width(), -deltaTop)); + invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(newBounds.x(), newBounds.y(), newBounds.width(), -deltaTop), invalidationReason); LayoutUnit deltaBottom = newBounds.maxY() - oldBounds.maxY(); if (deltaBottom > 0) - repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds.x(), oldBounds.maxY(), newBounds.width(), deltaBottom)); + invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(newBounds.x(), oldBounds.maxY(), newBounds.width(), deltaBottom), invalidationReason); else if (deltaBottom < 0) - repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds.x(), newBounds.maxY(), oldBounds.width(), -deltaBottom)); + invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(oldBounds.x(), newBounds.maxY(), oldBounds.width(), -deltaBottom), invalidationReason); - if (newOutlineBox == oldOutlineBox) + // FIXME: This is a limitation of our visual overflow being a single rectangle. + if (!style()->boxShadow() && !style()->hasBorderImageOutsets() && !style()->hasOutline()) return false; // We didn't move, but we did change size. Invalidate the delta, which will consist of possibly // two rectangles (but typically only one). - RenderStyle* outlineStyle = outlineStyleForRepaint(); + RenderStyle* outlineStyle = outlineStyleForPaintInvalidation(); LayoutUnit outlineWidth = outlineStyle->outlineSize(); LayoutBoxExtent insetShadowExtent = style()->getBoxShadowInsetExtent(); - LayoutUnit width = absoluteValue(newOutlineBox.width() - oldOutlineBox.width()); + LayoutUnit width = absoluteValue(newBounds.width() - oldBounds.width()); if (width) { LayoutUnit shadowLeft; LayoutUnit shadowRight; @@ -1566,19 +1751,20 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const RenderLayerModelObject* repa int borderRight = isBox() ? toRenderBox(this)->borderRight() : 0; LayoutUnit boxWidth = isBox() ? toRenderBox(this)->width() : LayoutUnit(); LayoutUnit minInsetRightShadowExtent = min<LayoutUnit>(-insetShadowExtent.right(), min<LayoutUnit>(newBounds.width(), oldBounds.width())); - LayoutUnit borderWidth = max<LayoutUnit>(borderRight, max<LayoutUnit>(valueForLength(style()->borderTopRightRadius().width(), boxWidth, v), valueForLength(style()->borderBottomRightRadius().width(), boxWidth, v))); - LayoutUnit decorationsWidth = max<LayoutUnit>(-outlineStyle->outlineOffset(), borderWidth + minInsetRightShadowExtent) + max<LayoutUnit>(outlineWidth, shadowRight); - LayoutRect rightRect(newOutlineBox.x() + min(newOutlineBox.width(), oldOutlineBox.width()) - decorationsWidth, - newOutlineBox.y(), - width + decorationsWidth, - max(newOutlineBox.height(), oldOutlineBox.height())); + LayoutUnit borderWidth = max<LayoutUnit>(borderRight, max<LayoutUnit>(valueForLength(style()->borderTopRightRadius().width(), boxWidth), valueForLength(style()->borderBottomRightRadius().width(), boxWidth))); + LayoutUnit decorationsLeftWidth = max<LayoutUnit>(-outlineStyle->outlineOffset(), borderWidth + minInsetRightShadowExtent) + max<LayoutUnit>(outlineWidth, -shadowLeft); + LayoutUnit decorationsRightWidth = max<LayoutUnit>(-outlineStyle->outlineOffset(), borderWidth + minInsetRightShadowExtent) + max<LayoutUnit>(outlineWidth, shadowRight); + LayoutRect rightRect(newBounds.x() + min(newBounds.width(), oldBounds.width()) - decorationsLeftWidth, + newBounds.y(), + width + decorationsLeftWidth + decorationsRightWidth, + max(newBounds.height(), oldBounds.height())); LayoutUnit right = min<LayoutUnit>(newBounds.maxX(), oldBounds.maxX()); if (rightRect.x() < right) { rightRect.setWidth(min(rightRect.width(), right - rightRect.x())); - repaintUsingContainer(repaintContainer, pixelSnappedIntRect(rightRect)); + invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(rightRect), invalidationReason); } } - LayoutUnit height = absoluteValue(newOutlineBox.height() - oldOutlineBox.height()); + LayoutUnit height = absoluteValue(newBounds.height() - oldBounds.height()); if (height) { LayoutUnit shadowTop; LayoutUnit shadowBottom; @@ -1586,46 +1772,58 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const RenderLayerModelObject* repa int borderBottom = isBox() ? toRenderBox(this)->borderBottom() : 0; LayoutUnit boxHeight = isBox() ? toRenderBox(this)->height() : LayoutUnit(); LayoutUnit minInsetBottomShadowExtent = min<LayoutUnit>(-insetShadowExtent.bottom(), min<LayoutUnit>(newBounds.height(), oldBounds.height())); - LayoutUnit borderHeight = max<LayoutUnit>(borderBottom, max<LayoutUnit>(valueForLength(style()->borderBottomLeftRadius().height(), boxHeight, v), valueForLength(style()->borderBottomRightRadius().height(), boxHeight, v))); - LayoutUnit decorationsHeight = max<LayoutUnit>(-outlineStyle->outlineOffset(), borderHeight + minInsetBottomShadowExtent) + max<LayoutUnit>(outlineWidth, shadowBottom); - LayoutRect bottomRect(newOutlineBox.x(), - min(newOutlineBox.maxY(), oldOutlineBox.maxY()) - decorationsHeight, - max(newOutlineBox.width(), oldOutlineBox.width()), - height + decorationsHeight); + LayoutUnit borderHeight = max<LayoutUnit>(borderBottom, max<LayoutUnit>(valueForLength(style()->borderBottomLeftRadius().height(), boxHeight), valueForLength(style()->borderBottomRightRadius().height(), boxHeight))); + LayoutUnit decorationsTopHeight = max<LayoutUnit>(-outlineStyle->outlineOffset(), borderHeight + minInsetBottomShadowExtent) + max<LayoutUnit>(outlineWidth, -shadowTop); + LayoutUnit decorationsBottomHeight = max<LayoutUnit>(-outlineStyle->outlineOffset(), borderHeight + minInsetBottomShadowExtent) + max<LayoutUnit>(outlineWidth, shadowBottom); + LayoutRect bottomRect(newBounds.x(), + min(newBounds.maxY(), oldBounds.maxY()) - decorationsTopHeight, + max(newBounds.width(), oldBounds.width()), + height + decorationsTopHeight + decorationsBottomHeight); LayoutUnit bottom = min(newBounds.maxY(), oldBounds.maxY()); if (bottomRect.y() < bottom) { bottomRect.setHeight(min(bottomRect.height(), bottom - bottomRect.y())); - repaintUsingContainer(repaintContainer, pixelSnappedIntRect(bottomRect)); + invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(bottomRect), invalidationReason); } } return false; } -void RenderObject::repaintOverflow() +void RenderObject::invalidatePaintForOverflow() +{ +} + +void RenderObject::invalidatePaintForOverflowIfNeeded() +{ + if (shouldInvalidateOverflowForPaint()) + invalidatePaintForOverflow(); +} + +bool RenderObject::checkForPaintInvalidation() const { + return !document().view()->needsFullPaintInvalidation() && everHadLayout(); } -bool RenderObject::checkForRepaintDuringLayout() const +bool RenderObject::checkForPaintInvalidationDuringLayout() const { - return !document().view()->needsFullRepaint() && !hasLayer() && everHadLayout(); + return !RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && checkForPaintInvalidation(); } -LayoutRect RenderObject::rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const +LayoutRect RenderObject::rectWithOutlineForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, LayoutUnit outlineWidth) const { - LayoutRect r(clippedOverflowRectForRepaint(repaintContainer)); + LayoutRect r(clippedOverflowRectForPaintInvalidation(paintInvalidationContainer)); r.inflate(outlineWidth); return r; } -LayoutRect RenderObject::clippedOverflowRectForRepaint(const RenderLayerModelObject*) const +LayoutRect RenderObject::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject*) const { ASSERT_NOT_REACHED(); return LayoutRect(); } -void RenderObject::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const +void RenderObject::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, bool fixed) const { - if (repaintContainer == this) + if (paintInvalidationContainer == this) return; if (RenderObject* o = parent()) { @@ -1642,11 +1840,11 @@ void RenderObject::computeRectForRepaint(const RenderLayerModelObject* repaintCo return; } - o->computeRectForRepaint(repaintContainer, rect, fixed); + o->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, fixed); } } -void RenderObject::computeFloatRectForRepaint(const RenderLayerModelObject*, FloatRect&, bool) const +void RenderObject::computeFloatRectForPaintInvalidation(const RenderLayerModelObject*, FloatRect&, bool) const { ASSERT_NOT_REACHED(); } @@ -1714,7 +1912,7 @@ void RenderObject::showRenderTreeAndMark(const RenderObject* markedObject1, cons if (!this) return; - for (const RenderObject* child = firstChild(); child; child = child->nextSibling()) + for (const RenderObject* child = slowFirstChild(); child; child = child->nextSibling()) child->showRenderTreeAndMark(markedObject1, markedLabel1, markedObject2, markedLabel2, depth + 1); } @@ -1727,19 +1925,14 @@ bool RenderObject::isSelectable() const Color RenderObject::selectionBackgroundColor() const { - Color backgroundColor; - if (isSelectable()) { - RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(PseudoStyleRequest(SELECTION)); - if (pseudoStyle && resolveColor(pseudoStyle.get(), CSSPropertyBackgroundColor).isValid()) { - backgroundColor = resolveColor(pseudoStyle.get(), CSSPropertyBackgroundColor).blendWithWhite(); - } else { - backgroundColor = frame()->selection().isFocusedAndActive() ? - RenderTheme::theme().activeSelectionBackgroundColor() : - RenderTheme::theme().inactiveSelectionBackgroundColor(); - } - } + if (!isSelectable()) + return Color::transparent; - return backgroundColor; + if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyleFromParentOrShadowHost()) + return resolveColor(pseudoStyle.get(), CSSPropertyBackgroundColor).blendWithWhite(); + return frame()->selection().isFocusedAndActive() ? + RenderTheme::theme().activeSelectionBackgroundColor() : + RenderTheme::theme().inactiveSelectionBackgroundColor(); } Color RenderObject::selectionColor(int colorProperty) const @@ -1747,19 +1940,15 @@ Color RenderObject::selectionColor(int colorProperty) const // If the element is unselectable, or we are only painting the selection, // don't override the foreground color with the selection foreground color. if (!isSelectable() || (frame()->view()->paintBehavior() & PaintBehaviorSelectionOnly)) - return Color::transparent; + return resolveColor(colorProperty); - Color color; - if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(PseudoStyleRequest(SELECTION))) { - Color selectionColor = resolveColor(pseudoStyle.get(), colorProperty); - color = selectionColor.isValid() ? selectionColor : resolveColor(pseudoStyle.get(), CSSPropertyColor); - } else { - color = frame()->selection().isFocusedAndActive() ? - RenderTheme::theme().activeSelectionForegroundColor() : - RenderTheme::theme().inactiveSelectionForegroundColor(); - } - - return color; + if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyleFromParentOrShadowHost()) + return resolveColor(pseudoStyle.get(), colorProperty); + if (!RenderTheme::theme().supportsSelectionForegroundColors()) + return resolveColor(colorProperty); + return frame()->selection().isFocusedAndActive() ? + RenderTheme::theme().activeSelectionForegroundColor() : + RenderTheme::theme().inactiveSelectionForegroundColor(); } Color RenderObject::selectionForegroundColor() const @@ -1796,65 +1985,57 @@ void RenderObject::handleDynamicFloatPositionChange() } } -void RenderObject::setAnimatableStyle(PassRefPtr<RenderStyle> style) -{ - if (!isText() && style && !RuntimeEnabledFeatures::webAnimationsCSSEnabled()) { - setStyle(animation().updateAnimations(*this, *style)); - return; - } - setStyle(style); -} - StyleDifference RenderObject::adjustStyleDifference(StyleDifference diff, unsigned contextSensitiveProperties) const { - // If transform changed, and the layer does not paint into its own separate backing, then we need to do a layout. - // FIXME: The comment above is what the code does, but it is technically not following spec. This means we will - // not to layout for 3d transforms, but we should be invoking a simplified relayout. Is it possible we are avoiding - // doing this for some performance reason at this time? + if (contextSensitiveProperties & ContextSensitivePropertyTransform && isSVG()) + diff.setNeedsFullLayout(); + + // If transform changed, and the layer does not paint into its own separate backing, then we need to invalidate paints. if (contextSensitiveProperties & ContextSensitivePropertyTransform) { // Text nodes share style with their parents but transforms don't apply to them, // hence the !isText() check. - // FIXME: when transforms are taken into account for overflow, we will need to do a layout. - if (!isText() && (!hasLayer() || toRenderLayerModelObject(this)->layer()->compositingState() != PaintsIntoOwnBacking)) { - // We need to set at least SimplifiedLayout, but if PositionedMovementOnly is already set - // then we actually need SimplifiedLayoutAndPositionedMovement. - if (!hasLayer()) - diff = StyleDifferenceLayout; // FIXME: Do this for now since SimplifiedLayout cannot handle updating floating objects lists. - else if (diff < StyleDifferenceLayoutPositionedMovementOnly) - diff = StyleDifferenceSimplifiedLayout; - else if (diff < StyleDifferenceSimplifiedLayout) - diff = StyleDifferenceSimplifiedLayoutAndPositionedMovement; - } else if (diff < StyleDifferenceRecompositeLayer) - diff = StyleDifferenceRecompositeLayer; - } - - // If opacity or filters changed, and the layer does not paint into its own separate backing, then we need to repaint (also + if (!isText() && (!hasLayer() || !toRenderLayerModelObject(this)->layer()->styleDeterminedCompositingReasons())) + diff.setNeedsRepaintLayer(); + else + diff.setNeedsRecompositeLayer(); + } + + // If opacity or zIndex changed, and the layer does not paint into its own separate backing, then we need to invalidate paints (also // ignoring text nodes) - if (contextSensitiveProperties & ContextSensitivePropertyOpacity && diff <= StyleDifferenceRepaintLayer) { - if (!isText() && (!hasLayer() || toRenderLayerModelObject(this)->layer()->compositingState() != PaintsIntoOwnBacking)) - diff = StyleDifferenceRepaintLayer; - else if (diff < StyleDifferenceRecompositeLayer) - diff = StyleDifferenceRecompositeLayer; + if (contextSensitiveProperties & (ContextSensitivePropertyOpacity | ContextSensitivePropertyZIndex)) { + if (!isText() && (!hasLayer() || !toRenderLayerModelObject(this)->layer()->styleDeterminedCompositingReasons())) + diff.setNeedsRepaintLayer(); + else + diff.setNeedsRecompositeLayer(); } - if ((contextSensitiveProperties & ContextSensitivePropertyFilter) && hasLayer() && diff <= StyleDifferenceRepaintLayer) { + + // If filter changed, and the layer does not paint into its own separate backing or it paints with filters, then we need to invalidate paints. + if ((contextSensitiveProperties & ContextSensitivePropertyFilter) && hasLayer()) { RenderLayer* layer = toRenderLayerModelObject(this)->layer(); - if (layer->compositingState() != PaintsIntoOwnBacking || layer->paintsWithFilters()) - diff = StyleDifferenceRepaintLayer; - else if (diff < StyleDifferenceRecompositeLayer) - diff = StyleDifferenceRecompositeLayer; + if (!layer->styleDeterminedCompositingReasons() || layer->paintsWithFilters()) + diff.setNeedsRepaintLayer(); + else + diff.setNeedsRecompositeLayer(); } - // The answer to requiresLayer() for plugins, iframes, and canvas can change without the actual + if ((contextSensitiveProperties & ContextSensitivePropertyTextOrColor) && !diff.needsRepaint() + && hasImmediateNonWhitespaceTextChildOrPropertiesDependentOnColor()) + diff.setNeedsRepaintObject(); + + // The answer to layerTypeRequired() for plugins, iframes, and canvas can change without the actual // style changing, 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. - if (diff == StyleDifferenceEqual && style() && isLayerModelObject()) { - if (hasLayer() != toRenderLayerModelObject(this)->requiresLayer()) - diff = StyleDifferenceLayout; + if (!diff.needsFullLayout() && style() && isLayerModelObject()) { + bool requiresLayer = toRenderLayerModelObject(this)->layerTypeRequired() != NoLayer; + if (hasLayer() != requiresLayer) + diff.setNeedsFullLayout(); } - // If we have no layer(), just treat a RepaintLayer hint as a normal Repaint. - if (diff == StyleDifferenceRepaintLayer && !hasLayer()) - diff = StyleDifferenceRepaint; + // If we have no layer(), just treat a RepaintLayer hint as a normal paint invalidation. + if (diff.needsRepaintLayer() && !hasLayer()) { + diff.clearNeedsRepaint(); + diff.setNeedsRepaintObject(); + } return diff; } @@ -1884,7 +2065,9 @@ void RenderObject::setPseudoStyle(PassRefPtr<RenderStyle> pseudoStyle) inline bool RenderObject::hasImmediateNonWhitespaceTextChildOrPropertiesDependentOnColor() const { - for (const RenderObject* r = firstChild(); r; r = r->nextSibling()) { + if (style()->hasBorder() || style()->hasOutline()) + return true; + for (const RenderObject* r = slowFirstChild(); r; r = r->nextSibling()) { if (r->isText() && !toRenderText(r)->isAllCollapsibleWhitespace()) return true; if (r->style()->hasOutline() || r->style()->hasBorder()) @@ -1893,13 +2076,24 @@ inline bool RenderObject::hasImmediateNonWhitespaceTextChildOrPropertiesDependen return false; } -inline bool RenderObject::shouldRepaintForStyleDifference(StyleDifference diff) const +void RenderObject::markContainingBlocksForOverflowRecalc() { - return diff == StyleDifferenceRepaint || (diff == StyleDifferenceRepaintIfTextOrColorChange && hasImmediateNonWhitespaceTextChildOrPropertiesDependentOnColor()); + for (RenderBlock* container = containingBlock(); container && !container->childNeedsOverflowRecalcAfterStyleChange(); container = container->containingBlock()) + container->setChildNeedsOverflowRecalcAfterStyleChange(true); +} + +void RenderObject::setNeedsOverflowRecalcAfterStyleChange() +{ + bool neededRecalc = needsOverflowRecalcAfterStyleChange(); + setSelfNeedsOverflowRecalcAfterStyleChange(true); + if (!neededRecalc) + markContainingBlocksForOverflowRecalc(); } void RenderObject::setStyle(PassRefPtr<RenderStyle> style) { + ASSERT(style); + if (m_style == style) { // We need to run through adjustStyleDifference() for iframes, plugins, and canvas so // style sharing is disabled for them. That should ensure that we never hit this code path. @@ -1907,14 +2101,14 @@ void RenderObject::setStyle(PassRefPtr<RenderStyle> style) return; } - StyleDifference diff = StyleDifferenceEqual; + StyleDifference diff; unsigned contextSensitiveProperties = ContextSensitivePropertyNone; if (m_style) - diff = m_style->diff(style.get(), contextSensitiveProperties); + diff = m_style->visualInvalidationDiff(*style, contextSensitiveProperties); diff = adjustStyleDifference(diff, contextSensitiveProperties); - styleWillChange(diff, style.get()); + styleWillChange(diff, *style); RefPtr<RenderStyle> oldStyle = m_style.release(); setStyleInternal(style); @@ -1925,15 +2119,8 @@ void RenderObject::setStyle(PassRefPtr<RenderStyle> style) updateImage(oldStyle ? oldStyle->borderImage().image() : 0, m_style ? m_style->borderImage().image() : 0); updateImage(oldStyle ? oldStyle->maskBoxImage().image() : 0, m_style ? m_style->maskBoxImage().image() : 0); - updateShapeImage(oldStyle ? oldStyle->shapeInside() : 0, m_style ? m_style->shapeInside() : 0); updateShapeImage(oldStyle ? oldStyle->shapeOutside() : 0, m_style ? m_style->shapeOutside() : 0); - // We need to ensure that view->maximalOutlineSize() is valid for any repaints that happen - // during styleDidChange (it's used by clippedOverflowRectForRepaint()). - // FIXME: Do this more cleanly. http://crbug.com/273904 - if (m_style->outlineWidth() > 0 && m_style->outlineSize() > view()->maximalOutlineSize()) - view()->setMaximalOutlineSize(m_style->outlineSize()); - bool doesNotNeedLayout = !m_parent || isText(); styleDidChange(diff, oldStyle.get()); @@ -1946,25 +2133,28 @@ void RenderObject::setStyle(PassRefPtr<RenderStyle> style) return; // Now that the layer (if any) has been updated, we need to adjust the diff again, - // check whether we should layout now, and decide if we need to repaint. + // check whether we should layout now, and decide if we need to invalidate paints. StyleDifference updatedDiff = adjustStyleDifference(diff, contextSensitiveProperties); - if (diff <= StyleDifferenceLayoutPositionedMovementOnly) { - if (updatedDiff == StyleDifferenceLayout) + if (!diff.needsFullLayout()) { + if (updatedDiff.needsFullLayout()) setNeedsLayoutAndPrefWidthsRecalc(); - else if (updatedDiff == StyleDifferenceLayoutPositionedMovementOnly) - setNeedsPositionedMovementLayout(); - else if (updatedDiff == StyleDifferenceSimplifiedLayoutAndPositionedMovement) { + else if (updatedDiff.needsPositionedMovementLayout()) setNeedsPositionedMovementLayout(); - setNeedsSimplifiedNormalFlowLayout(); - } else if (updatedDiff == StyleDifferenceSimplifiedLayout) - setNeedsSimplifiedNormalFlowLayout(); } - if (updatedDiff == StyleDifferenceRepaintLayer || shouldRepaintForStyleDifference(updatedDiff)) { - // Do a repaint with the new style now, e.g., for example if we go from - // not having an outline to having an outline. - repaint(); + if (contextSensitiveProperties & ContextSensitivePropertyTransform && !needsLayout()) { + if (RenderBlock* container = containingBlock()) + container->setNeedsOverflowRecalcAfterStyleChange(); + } + + if (updatedDiff.needsRepaint()) { + // Invalidate paints with the new style, e.g., for example if we go from not having + // an outline to having an outline. + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && needsLayout()) + setShouldDoFullPaintInvalidationAfterLayout(true); + else if (!selfNeedsLayout()) + paintInvalidationForWholeRenderer(); } } @@ -1973,76 +2163,80 @@ static inline bool rendererHasBackground(const RenderObject* renderer) return renderer && renderer->hasBackground(); } -void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) +void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle& newStyle) { if (m_style) { // If our z-index changes value or our visibility changes, // we need to dirty our stacking context's z-order list. - if (newStyle) { - bool visibilityChanged = m_style->visibility() != newStyle->visibility() - || m_style->zIndex() != newStyle->zIndex() - || m_style->hasAutoZIndex() != newStyle->hasAutoZIndex(); - if (visibilityChanged) { - document().setAnnotatedRegionsDirty(true); - if (AXObjectCache* cache = document().existingAXObjectCache()) - cache->childrenChanged(parent()); - } + bool visibilityChanged = m_style->visibility() != newStyle.visibility() + || m_style->zIndex() != newStyle.zIndex() + || m_style->hasAutoZIndex() != newStyle.hasAutoZIndex(); + if (visibilityChanged) { + document().setAnnotatedRegionsDirty(true); + if (AXObjectCache* cache = document().existingAXObjectCache()) + cache->childrenChanged(parent()); + } - // Keep layer hierarchy visibility bits up to date if visibility changes. - if (m_style->visibility() != newStyle->visibility()) { - if (RenderLayer* l = enclosingLayer()) { - if (newStyle->visibility() == VISIBLE) - l->setHasVisibleContent(); - else if (l->hasVisibleContent() && (this == l->renderer() || l->renderer()->style()->visibility() != VISIBLE)) { - l->dirtyVisibleContentStatus(); - if (diff > StyleDifferenceRepaintLayer) - repaint(); - } + // Keep layer hierarchy visibility bits up to date if visibility changes. + if (m_style->visibility() != newStyle.visibility()) { + // We might not have an enclosing layer yet because we might not be in the tree. + if (RenderLayer* layer = enclosingLayer()) { + if (newStyle.visibility() == VISIBLE) { + layer->setHasVisibleContent(); + } else if (layer->hasVisibleContent() && (this == layer->renderer() || layer->renderer()->style()->visibility() != VISIBLE)) { + layer->dirtyVisibleContentStatus(); + if (diff.needsLayout()) + paintInvalidationForWholeRenderer(); } } } - if (m_parent && (newStyle->outlineSize() < m_style->outlineSize() || shouldRepaintForStyleDifference(diff))) - repaint(); - if (isFloating() && (m_style->floating() != newStyle->floating())) + if (m_parent && diff.needsRepaintObject()) { + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && (diff.needsLayout() || needsLayout())) + setShouldDoFullPaintInvalidationAfterLayout(true); + else if (!diff.needsFullLayout() && !selfNeedsLayout()) + paintInvalidationForWholeRenderer(); + } + + if (isFloating() && (m_style->floating() != newStyle.floating())) // For changes in float styles, we need to conceivably remove ourselves // from the floating objects list. toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists(); - else if (isOutOfFlowPositioned() && (m_style->position() != newStyle->position())) + else if (isOutOfFlowPositioned() && (m_style->position() != newStyle.position())) // For changes in positioning styles, we need to conceivably remove ourselves // from the positioned objects list. toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists(); s_affectsParentBlock = isFloatingOrOutOfFlowPositioned() - && (!newStyle->isFloating() && !newStyle->hasOutOfFlowPosition()) + && (!newStyle.isFloating() && !newStyle.hasOutOfFlowPosition()) && parent() && (parent()->isRenderBlockFlow() || parent()->isRenderInline()); // Clearing these bits is required to avoid leaving stale renderers. // FIXME: We shouldn't need that hack if our logic was totally correct. - if (diff == StyleDifferenceLayout || diff == StyleDifferenceLayoutPositionedMovementOnly) { + if (diff.needsLayout()) { setFloating(false); clearPositionedState(); } - } else + } else { s_affectsParentBlock = false; + } if (view()->frameView()) { bool shouldBlitOnFixedBackgroundImage = false; -#if ENABLE(FAST_MOBILE_SCROLLING) - // On low-powered/mobile devices, preventing blitting on a scroll can cause noticeable delays - // 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; -#endif - - bool newStyleSlowScroll = newStyle && !shouldBlitOnFixedBackgroundImage && newStyle->hasFixedBackgroundImage(); + if (RuntimeEnabledFeatures::fastMobileScrollingEnabled()) { + // On low-powered/mobile devices, preventing blitting on a scroll can cause noticeable delays + // 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; + } + bool newStyleSlowScroll = !shouldBlitOnFixedBackgroundImage && newStyle.hasFixedBackgroundImage(); bool oldStyleSlowScroll = m_style && !shouldBlitOnFixedBackgroundImage && m_style->hasFixedBackgroundImage(); - bool drawsRootBackground = isRoot() || (isBody() && !rendererHasBackground(document().documentElement()->renderer())); + bool drawsRootBackground = isDocumentElement() || (isBody() && !rendererHasBackground(document().documentElement()->renderer())); if (drawsRootBackground && !shouldBlitOnFixedBackgroundImage) { if (view()->compositor()->supportsFixedRootBackgroundCompositing()) { - if (newStyleSlowScroll && newStyle->hasEntirelyFixedBackground()) + if (newStyleSlowScroll && newStyle.hasEntirelyFixedBackground()) newStyleSlowScroll = false; if (oldStyleSlowScroll && m_style->hasEntirelyFixedBackground()) @@ -2057,6 +2251,20 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS view()->frameView()->addSlowRepaintObject(); } } + + // Elements with non-auto touch-action will send a SetTouchAction message + // on touchstart in EventHandler::handleTouchEvent, and so effectively have + // a touchstart handler that must be reported. + // + // Since a CSS property cannot be applied directly to a text node, a + // handler will have already been added for its parent so ignore it. + TouchAction oldTouchAction = m_style ? m_style->touchAction() : TouchActionAuto; + if (node() && !node()->isTextNode() && (oldTouchAction == TouchActionAuto) != (newStyle.touchAction() == TouchActionAuto)) { + if (newStyle.touchAction() != TouchActionAuto) + document().didAddTouchEventHandler(node()); + else + document().didRemoveTouchEventHandler(node()); + } } static bool areNonIdenticalCursorListsEqual(const RenderStyle* a, const RenderStyle* b) @@ -2078,7 +2286,7 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldSt if (!m_parent) return; - if (diff == StyleDifferenceLayout || diff == StyleDifferenceSimplifiedLayout) { + if (diff.needsFullLayout()) { RenderCounter::rendererStyleChanged(*this, oldStyle, m_style.get()); // If the object already needs layout, then setNeedsLayout won't do @@ -2089,21 +2297,20 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldSt if (needsLayout() && oldStyle->position() != m_style->position()) markContainingBlocksForLayout(); - if (diff == StyleDifferenceLayout) + // Ditto. + if (needsOverflowRecalcAfterStyleChange() && oldStyle->position() != m_style->position()) + markContainingBlocksForOverflowRecalc(); + + if (diff.needsFullLayout()) setNeedsLayoutAndPrefWidthsRecalc(); - else - setNeedsSimplifiedNormalFlowLayout(); - } else if (diff == StyleDifferenceSimplifiedLayoutAndPositionedMovement) { - setNeedsPositionedMovementLayout(); - setNeedsSimplifiedNormalFlowLayout(); - } else if (diff == StyleDifferenceLayoutPositionedMovementOnly) + } else if (diff.needsPositionedMovementLayout()) setNeedsPositionedMovementLayout(); - // Don't check for repaint here; we need to wait until the layer has been - // updated by subclasses before we know if we have to repaint (in setStyle()). + // Don't check for paint invalidation here; we need to wait until the layer has been + // updated by subclasses before we know if we have to invalidate paints (in setStyle()). if (oldStyle && !areCursorsEqual(oldStyle, style())) { - if (Frame* frame = this->frame()) + if (LocalFrame* frame = this->frame()) frame->eventHandler().scheduleCursorUpdate(); } } @@ -2111,7 +2318,7 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldSt void RenderObject::propagateStyleToAnonymousChildren(bool blockChildrenOnly) { // FIXME: We could save this call when the change only affected non-inherited properties. - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { + for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling()) { if (!child->isAnonymous() || child->style()->styleType() != NOPSEUDO) continue; @@ -2203,9 +2410,9 @@ FloatQuad RenderObject::absoluteToLocalQuad(const FloatQuad& quad, MapCoordinate return transformState.lastPlanarQuad(); } -void RenderObject::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const +void RenderObject::mapLocalToContainer(const RenderLayerModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const { - if (repaintContainer == this) + if (paintInvalidationContainer == this) return; RenderObject* o = parent(); @@ -2220,15 +2427,12 @@ void RenderObject::mapLocalToContainer(const RenderLayerModelObject* repaintCont mode &= ~ApplyContainerFlip; } - LayoutSize columnOffset; - o->adjustForColumns(columnOffset, roundedLayoutPoint(transformState.mappedPoint())); - if (!columnOffset.isZero()) - transformState.move(columnOffset); + transformState.move(o->columnOffset(roundedLayoutPoint(transformState.mappedPoint()))); if (o->hasOverflowClip()) transformState.move(-toRenderBox(o)->scrolledContentOffset()); - o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed); + o->mapLocalToContainer(paintInvalidationContainer, transformState, mode, wasFixed); } const RenderObject* RenderObject::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const @@ -2269,7 +2473,7 @@ bool RenderObject::shouldUseTransformFromContainer(const RenderObject* container void RenderObject::getTransformFromContainer(const RenderObject* containerObject, const LayoutSize& offsetInContainer, TransformationMatrix& transform) const { transform.makeIdentity(); - transform.translate(offsetInContainer.width(), offsetInContainer.height()); + transform.translate(offsetInContainer.width().toFloat(), offsetInContainer.height().toFloat()); RenderLayer* layer; if (hasLayer() && (layer = toRenderLayerModelObject(this)->layer()) && layer->transform()) transform.multiply(layer->currentTransform()); @@ -2288,33 +2492,31 @@ void RenderObject::getTransformFromContainer(const RenderObject* containerObject } } -FloatQuad RenderObject::localToContainerQuad(const FloatQuad& localQuad, const RenderLayerModelObject* repaintContainer, MapCoordinatesFlags mode, bool* wasFixed) const +FloatQuad RenderObject::localToContainerQuad(const FloatQuad& localQuad, const RenderLayerModelObject* paintInvalidationContainer, MapCoordinatesFlags mode, bool* wasFixed) const { // 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, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed); + mapLocalToContainer(paintInvalidationContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed); transformState.flatten(); return transformState.lastPlanarQuad(); } -FloatPoint RenderObject::localToContainerPoint(const FloatPoint& localPoint, const RenderLayerModelObject* repaintContainer, MapCoordinatesFlags mode, bool* wasFixed) const +FloatPoint RenderObject::localToContainerPoint(const FloatPoint& localPoint, const RenderLayerModelObject* paintInvalidationContainer, MapCoordinatesFlags mode, bool* wasFixed) const { TransformState transformState(TransformState::ApplyTransformDirection, localPoint); - mapLocalToContainer(repaintContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed); + mapLocalToContainer(paintInvalidationContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed); transformState.flatten(); return transformState.lastPlanarPoint(); } -LayoutSize RenderObject::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const +LayoutSize RenderObject::offsetFromContainer(const RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const { ASSERT(o == container()); - LayoutSize offset; - - o->adjustForColumns(offset, point); + LayoutSize offset = o->columnOffset(point); if (o->hasOverflowClip()) offset -= toRenderBox(o)->scrolledContentOffset(); @@ -2325,13 +2527,13 @@ LayoutSize RenderObject::offsetFromContainer(RenderObject* o, const LayoutPoint& return offset; } -LayoutSize RenderObject::offsetFromAncestorContainer(RenderObject* container) const +LayoutSize RenderObject::offsetFromAncestorContainer(const RenderObject* container) const { LayoutSize offset; LayoutPoint referencePoint; const RenderObject* currContainer = this; do { - RenderObject* nextContainer = currContainer->container(); + const RenderObject* nextContainer = currContainer->container(); ASSERT(nextContainer); // This means we reached the top without finding container. if (!nextContainer) break; @@ -2362,21 +2564,15 @@ void RenderObject::computeLayerHitTestRects(LayerHitTestRects& layerRects) const if (!hasLayer()) { RenderObject* container = this->container(); - if (container) { - currentLayer = container->enclosingLayer(); - if (currentLayer && currentLayer->renderer() != container) { - layerOffset.move(container->offsetFromAncestorContainer(currentLayer->renderer())); - // If the layer itself is scrolled, we have to undo the subtraction of its scroll - // offset since we want the offset relative to the scrolling content, not the - // element itself. - if (currentLayer->renderer()->hasOverflowClip()) - layerOffset.move(currentLayer->renderBox()->scrolledContentOffset()); - } - } else { - currentLayer = enclosingLayer(); + currentLayer = container->enclosingLayer(); + if (container && currentLayer->renderer() != container) { + layerOffset.move(container->offsetFromAncestorContainer(currentLayer->renderer())); + // If the layer itself is scrolled, we have to undo the subtraction of its scroll + // offset since we want the offset relative to the scrolling content, not the + // element itself. + if (currentLayer->renderer()->hasOverflowClip()) + layerOffset.move(currentLayer->renderBox()->scrolledContentOffset()); } - if (!currentLayer) - return; } this->addLayerHitTestRects(layerRects, currentLayer, layerOffset, LayoutRect()); @@ -2401,12 +2597,15 @@ void RenderObject::addLayerHitTestRects(LayerHitTestRects& layerRects, const Ren const size_t maxRectsPerLayer = 100; LayerHitTestRects::iterator iter = layerRects.find(currentLayer); + Vector<WebCore::LayoutRect>* iterValue; if (iter == layerRects.end()) - iter = layerRects.add(currentLayer, Vector<LayoutRect>()).iterator; + iterValue = &layerRects.add(currentLayer, Vector<LayoutRect>()).storedValue->value; + else + iterValue = &iter->value; for (size_t i = 0; i < ownRects.size(); i++) { if (!containerRect.contains(ownRects[i])) { - iter->value.append(ownRects[i]); - if (iter->value.size() > maxRectsPerLayer) { + iterValue->append(ownRects[i]); + if (iterValue->size() > maxRectsPerLayer) { // Just mark the entire layer instead, and switch to walking the layer // tree instead of the render tree. layerRects.remove(currentLayer); @@ -2428,31 +2627,26 @@ void RenderObject::addLayerHitTestRects(LayerHitTestRects& layerRects, const Ren // partially redundant rectangles. If we find examples where this is expensive, then we could // rewrite Region to be more efficient. See https://bugs.webkit.org/show_bug.cgi?id=100814. if (!isRenderView()) { - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling()) { curr->addLayerHitTestRects(layerRects, currentLayer, layerOffset, newContainerRect); } } } -bool RenderObject::isRooted(RenderView** view) const +bool RenderObject::isRooted() const { - const RenderObject* o = this; - while (o->parent()) - o = o->parent(); - - if (!o->isRenderView()) - return false; - - if (view) - *view = const_cast<RenderView*>(toRenderView(o)); - - return true; + const RenderObject* object = this; + while (object->parent() && !object->hasLayer()) + object = object->parent(); + if (object->hasLayer()) + return toRenderLayerModelObject(object)->layer()->root()->isRootLayer(); + return false; } RenderObject* RenderObject::rendererForRootBackground() { - ASSERT(isRoot()); - if (!hasBackground() && node() && isHTMLHtmlElement(node())) { + ASSERT(isDocumentElement()); + if (!hasBackground() && isHTMLHtmlElement(node())) { // Locate the <body> element using the DOM. This is easier than trying // to crawl around a render tree with potential :before/:after content and // anonymous blocks created by inline <body> tags etc. We can locate the <body> @@ -2471,7 +2665,7 @@ 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; + || (document().settings() && document().settings()->shouldRespectImageOrientation() && isHTMLImageElement(node())) ? RespectImageOrientation : DoNotRespectImageOrientation; } bool RenderObject::hasOutlineAnnotation() const @@ -2484,10 +2678,10 @@ bool RenderObject::hasEntirelyFixedBackground() const return m_style->hasEntirelyFixedBackground(); } -RenderObject* RenderObject::container(const RenderLayerModelObject* repaintContainer, bool* repaintContainerSkipped) const +RenderObject* RenderObject::container(const RenderLayerModelObject* paintInvalidationContainer, bool* paintInvalidationContainerSkipped) const { - if (repaintContainerSkipped) - *repaintContainerSkipped = false; + if (paintInvalidationContainerSkipped) + *paintInvalidationContainerSkipped = false; // This method is extremely similar to containingBlock(), but with a few notable // exceptions. @@ -2505,7 +2699,7 @@ RenderObject* RenderObject::container(const RenderLayerModelObject* repaintConta EPosition pos = m_style->position(); if (pos == FixedPosition) { - return containerForFixedPosition(repaintContainer, repaintContainerSkipped); + return containerForFixedPosition(paintInvalidationContainer, paintInvalidationContainerSkipped); } else if (pos == AbsolutePosition) { // We technically just want our containing block, but // we may not have one if we're part of an uninstalled @@ -2517,8 +2711,8 @@ RenderObject* RenderObject::container(const RenderLayerModelObject* repaintConta if (o->canContainFixedPositionObjects()) break; - if (repaintContainerSkipped && o == repaintContainer) - *repaintContainerSkipped = true; + if (paintInvalidationContainerSkipped && o == paintInvalidationContainer) + *paintInvalidationContainerSkipped = true; o = o->parent(); } @@ -2543,7 +2737,7 @@ inline void RenderObject::clearLayoutRootIfNeeded() const // This indicates a failure to layout the child, which is why // the layout root is still set to |this|. Make sure to clear it // since we are getting destroyed. - view->clearLayoutRoot(); + view->clearLayoutSubtreeRoot(); } } } @@ -2557,10 +2751,9 @@ void RenderObject::willBeDestroyed() children->destroyLeftoverChildren(); // If this renderer is being autoscrolled, stop the autoscrolling. - if (Frame* frame = this->frame()) { + if (LocalFrame* frame = this->frame()) { if (frame->page()) frame->page()->autoscrollController().stopAutoscrollIfNeeded(this); - frame->animation().cancelAnimations(this); } // For accessibility management, notify the parent of the imminent change to its child set. @@ -2575,18 +2768,6 @@ void RenderObject::willBeDestroyed() if (AXObjectCache* cache = document().existingAXObjectCache()) cache->remove(this); -#ifndef NDEBUG - if (!documentBeingDestroyed() && view() && view()->hasRenderNamedFlowThreads()) { - // After remove, the object and the associated information should not be in any flow thread. - 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)); - } - } -#endif - // If this renderer had a parent, remove should have destroyed any counters // attached to this renderer and marked the affected other counters for // reevaluation. This apparently redundant check is here for the case when @@ -2595,6 +2776,13 @@ void RenderObject::willBeDestroyed() if (hasCounterNodeMap()) RenderCounter::destroyCounterNodes(*this); + // Remove the handler if node had touch-action set. Don't call when + // document is being destroyed as all handlers will have been cleared + // previously. Handlers are not added for text nodes so don't try removing + // for one too. Need to check if m_style is null in cases of partial construction. + if (!documentBeingDestroyed() && node() && !node()->isTextNode() && m_style && m_style->touchAction() != TouchActionAuto) + document().didRemoveTouchEventHandler(node()); + setAncestorLineBoxDirty(false); clearLayoutRootIfNeeded(); @@ -2607,7 +2795,7 @@ void RenderObject::insertedIntoTree() // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children // and don't have a layer attached to ourselves. RenderLayer* layer = 0; - if (firstChild() || hasLayer()) { + if (slowFirstChild() || hasLayer()) { layer = parent()->enclosingLayer(); addLayers(layer); } @@ -2623,9 +2811,6 @@ void RenderObject::insertedIntoTree() if (!isFloating() && parent()->childrenInline()) parent()->dirtyLinesFromChangedChild(this); - - if (RenderNamedFlowThread* containerFlowThread = parent()->renderNamedFlowThreadWrapper()) - containerFlowThread->addFlowChild(this); } void RenderObject::willBeRemovedFromTree() @@ -2635,12 +2820,13 @@ void RenderObject::willBeRemovedFromTree() // If we remove a visible child from an invisible parent, we don't know the layer visibility any more. RenderLayer* layer = 0; if (parent()->style()->visibility() != VISIBLE && style()->visibility() == VISIBLE && !hasLayer()) { - if ((layer = parent()->enclosingLayer())) + layer = parent()->enclosingLayer(); + if (layer) layer->dirtyVisibleContentStatus(); } // Keep our layer hierarchy updated. - if (firstChild() || hasLayer()) { + if (slowFirstChild() || hasLayer()) { if (!layer) layer = parent()->enclosingLayer(); removeLayers(layer); @@ -2651,11 +2837,9 @@ void RenderObject::willBeRemovedFromTree() removeFromRenderFlowThread(); - if (RenderNamedFlowThread* containerFlowThread = parent()->renderNamedFlowThreadWrapper()) - containerFlowThread->removeFlowChild(this); - // Update cached boundaries in SVG renderers if a child is removed. - parent()->setNeedsBoundariesUpdate(); + if (parent()->isSVG()) + parent()->setNeedsBoundariesUpdate(); } void RenderObject::removeFromRenderFlowThread() @@ -2677,11 +2861,6 @@ void RenderObject::removeFromRenderFlowThreadRecursive(RenderFlowThread* renderF child->removeFromRenderFlowThreadRecursive(renderFlowThread); } - RenderFlowThread* localFlowThread = renderFlowThread; - if (flowThreadState() == InsideInFlowThread) - localFlowThread = flowThreadContainingBlock(); // We have to ask. We can't just assume we are in the same flow thread. - if (localFlowThread) - localFlowThread->removeFlowChildInfo(this); setFlowThreadState(NotInsideFlowThread); } @@ -2703,7 +2882,7 @@ void RenderObject::destroyAndCleanupAnonymousWrappers() if (destroyRootParent->isRenderFlowThread() || destroyRootParent->isAnonymousColumnSpanBlock()) break; - if (destroyRootParent->firstChild() != this || destroyRootParent->lastChild() != this) + if (destroyRootParent->slowFirstChild() != this || destroyRootParent->slowLastChild() != this) break; } @@ -2712,6 +2891,12 @@ void RenderObject::destroyAndCleanupAnonymousWrappers() // WARNING: |this| is deleted here. } +void RenderObject::destroy() +{ + willBeDestroyed(); + postDestroy(); +} + void RenderObject::removeShapeImageClient(ShapeValue* shapeValue) { if (!shapeValue) @@ -2720,12 +2905,6 @@ void RenderObject::removeShapeImageClient(ShapeValue* shapeValue) shapeImage->removeClient(this); } -void RenderObject::destroy() -{ - willBeDestroyed(); - postDestroy(); -} - void RenderObject::postDestroy() { // It seems ugly that this is not in willBeDestroyed(). @@ -2746,7 +2925,6 @@ void RenderObject::postDestroy() if (StyleImage* maskBoxImage = m_style->maskBoxImage().image()) maskBoxImage->removeClient(this); - removeShapeImageClient(m_style->shapeInside()); removeShapeImageClient(m_style->shapeOutside()); } @@ -2762,9 +2940,13 @@ void RenderObject::updateDragState(bool dragOn) { bool valueChanged = (dragOn != isDragging()); setIsDragging(dragOn); - if (valueChanged && node() && (style()->affectedByDrag() || (node()->isElementNode() && toElement(node())->childrenAffectedByDrag()))) - node()->setNeedsStyleRecalc(); - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) + if (valueChanged && node()) { + if (node()->isElementNode() && toElement(node())->childrenOrSiblingsAffectedByDrag()) + node()->setNeedsStyleRecalc(SubtreeStyleChange); + else if (style()->affectedByDrag()) + node()->setNeedsStyleRecalc(LocalStyleChange); + } + for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling()) curr->updateDragState(dragOn); } @@ -2773,6 +2955,11 @@ CompositingState RenderObject::compositingState() const return hasLayer() ? toRenderLayerModelObject(this)->layer()->compositingState() : NotComposited; } +CompositingReasons RenderObject::additionalCompositingReasons(CompositingTriggerFlags) const +{ + return CompositingReasonNone; +} + bool RenderObject::hitTest(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestFilter hitTestFilter) { bool inside = false; @@ -2839,35 +3026,10 @@ void RenderObject::scheduleRelayout() } } -void RenderObject::layout() -{ - ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); - RenderObject* child = firstChild(); - while (child) { - child->layoutIfNeeded(); - ASSERT(!child->needsLayout()); - child = child->nextSibling(); - } - clearNeedsLayout(); -} - -void RenderObject::didLayout(ResourceLoadPriorityOptimizer& priorityModifier) -{ - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) - child->didLayout(priorityModifier); -} - -void RenderObject::didScroll(ResourceLoadPriorityOptimizer& priorityModifier) -{ - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) - child->didScroll(priorityModifier); -} - void RenderObject::forceLayout() { setSelfNeedsLayout(true); - setShouldDoFullRepaintAfterLayout(true); + setShouldDoFullPaintInvalidationAfterLayout(true); layout(); } @@ -2907,13 +3069,13 @@ static PassRefPtr<RenderStyle> firstLineStyleForCachedUncachedType(StyleCacheSta return rendererForFirstLineStyle->getUncachedPseudoStyle(PseudoStyleRequest(FIRST_LINE_INHERITED), parentStyle, style); } } - return 0; + return nullptr; } PassRefPtr<RenderStyle> RenderObject::uncachedFirstLineStyle(RenderStyle* style) const { if (!document().styleEngine()->usesFirstLineRules()) - return 0; + return nullptr; ASSERT(!isText()); @@ -2948,20 +3110,19 @@ RenderStyle* RenderObject::getCachedPseudoStyle(PseudoId pseudo, RenderStyle* pa PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle, RenderStyle* ownStyle) const { if (pseudoStyleRequest.pseudoId < FIRST_INTERNAL_PSEUDOID && !ownStyle && !style()->hasPseudoStyle(pseudoStyleRequest.pseudoId)) - return 0; + return nullptr; if (!parentStyle) { ASSERT(!ownStyle); 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); + if (!node()) + return nullptr; + + Element* element = Traversal<Element>::firstAncestorOrSelf(*node()); + if (!element) + return nullptr; if (pseudoStyleRequest.pseudoId == FIRST_LINE_INHERITED) { RefPtr<RenderStyle> result = document().ensureStyleResolver().styleForElement(element, parentStyle, DisallowStyleSharing); @@ -2972,54 +3133,56 @@ PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(const PseudoStyleRe return document().ensureStyleResolver().pseudoStyleForElement(element, pseudoStyleRequest, parentStyle); } -bool RenderObject::hasBlendMode() const +PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyleFromParentOrShadowHost() const { - return RuntimeEnabledFeatures::cssCompositingEnabled() && style() && style()->hasBlendMode(); -} + if (!node()) + return nullptr; -static Color decorationColor(const RenderObject* object, RenderStyle* style) -{ - Color result; - // Check for text decoration color first. - result = object->resolveColor(style, CSSPropertyTextDecorationColor); - if (result.isValid()) - return result; - if (style->textStrokeWidth() > 0) { - // Prefer stroke color if possible but not if it's fully transparent. - result = object->resolveColor(style, CSSPropertyWebkitTextStrokeColor); - if (result.alpha()) - return result; + if (ShadowRoot* root = node()->containingShadowRoot()) { + if (root->type() == ShadowRoot::UserAgentShadowRoot) { + if (Element* shadowHost = node()->shadowHost()) { + return shadowHost->renderer()->getUncachedPseudoStyle(PseudoStyleRequest(SELECTION)); + } + } } - result = object->resolveColor(style, CSSPropertyWebkitTextFillColor); - return result; + return getUncachedPseudoStyle(PseudoStyleRequest(SELECTION)); +} + +bool RenderObject::hasBlendMode() const +{ + return RuntimeEnabledFeatures::cssCompositingEnabled() && style() && style()->hasBlendMode(); } -void RenderObject::getTextDecorationColors(unsigned decorations, Color& underline, Color& overline, - Color& linethrough, bool quirksMode, bool firstlineStyle) +void RenderObject::getTextDecorations(unsigned decorations, AppliedTextDecoration& underline, AppliedTextDecoration& overline, AppliedTextDecoration& linethrough, bool quirksMode, bool firstlineStyle) { RenderObject* curr = this; RenderStyle* styleToUse = 0; unsigned currDecs = TextDecorationNone; Color resultColor; + TextDecorationStyle resultStyle; do { styleToUse = curr->style(firstlineStyle); currDecs = styleToUse->textDecoration(); currDecs &= decorations; - resultColor = decorationColor(this, styleToUse); + resultColor = styleToUse->visitedDependentDecorationColor(); + resultStyle = styleToUse->textDecorationStyle(); // Parameter 'decorations' is cast as an int to enable the bitwise operations below. if (currDecs) { if (currDecs & TextDecorationUnderline) { decorations &= ~TextDecorationUnderline; - underline = resultColor; + underline.color = resultColor; + underline.style = resultStyle; } if (currDecs & TextDecorationOverline) { decorations &= ~TextDecorationOverline; - overline = resultColor; + overline.color = resultColor; + overline.style = resultStyle; } if (currDecs & TextDecorationLineThrough) { decorations &= ~TextDecorationLineThrough; - linethrough = resultColor; + linethrough.color = resultColor; + linethrough.style = resultStyle; } } if (curr->isRubyText()) @@ -3027,18 +3190,24 @@ void RenderObject::getTextDecorationColors(unsigned decorations, Color& underlin curr = curr->parent(); if (curr && curr->isAnonymousBlock() && toRenderBlock(curr)->continuation()) curr = toRenderBlock(curr)->continuation(); - } while (curr && decorations && (!quirksMode || !curr->node() || (!isHTMLAnchorElement(curr->node()) && !curr->node()->hasTagName(fontTag)))); + } while (curr && decorations && (!quirksMode || !curr->node() || (!isHTMLAnchorElement(*curr->node()) && !isHTMLFontElement(*curr->node())))); // If we bailed out, use the element we bailed out at (typically a <font> or <a> element). if (decorations && curr) { styleToUse = curr->style(firstlineStyle); - resultColor = decorationColor(this, styleToUse); - if (decorations & TextDecorationUnderline) - underline = resultColor; - if (decorations & TextDecorationOverline) - overline = resultColor; - if (decorations & TextDecorationLineThrough) - linethrough = resultColor; + resultColor = styleToUse->visitedDependentDecorationColor(); + if (decorations & TextDecorationUnderline) { + underline.color = resultColor; + underline.style = resultStyle; + } + if (decorations & TextDecorationOverline) { + overline.color = resultColor; + overline.style = resultStyle; + } + if (decorations & TextDecorationLineThrough) { + linethrough.color = resultColor; + linethrough.style = resultStyle; + } } } @@ -3052,7 +3221,7 @@ void RenderObject::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions) return; RenderBox* box = toRenderBox(this); - FloatRect localBounds(FloatPoint(), FloatSize(box->width(), box->height())); + FloatRect localBounds(FloatPoint(), FloatSize(box->width().toFloat(), box->height().toFloat())); FloatRect absBounds = localToAbsoluteQuad(localBounds).boundingBox(); AnnotatedRegionValue region; @@ -3069,7 +3238,7 @@ void RenderObject::collectAnnotatedRegions(Vector<AnnotatedRegionValue>& regions return; addAnnotatedRegions(regions); - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) + for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling()) curr->collectAnnotatedRegions(regions); } @@ -3085,14 +3254,7 @@ bool RenderObject::willRenderImage(ImageResource*) // If we're not in a window (i.e., we're dormant from being in a background tab) // then we don't want to render either. - return !document().view()->isOffscreen(); -} - -int RenderObject::maximalOutlineSize(PaintPhase p) const -{ - if (p != PaintPhaseOutline && p != PaintPhaseSelfOutline && p != PaintPhaseChildOutlines) - return 0; - return view()->maximalOutlineSize(); + return document().view()->isVisible(); } int RenderObject::caretMinOffset() const @@ -3103,7 +3265,7 @@ int RenderObject::caretMinOffset() const int RenderObject::caretMaxOffset() const { if (isReplaced()) - return node() ? max(1U, node()->childNodeCount()) : 1; + return node() ? max(1U, node()->countChildren()) : 1; if (isHR()) return 1; return 0; @@ -3124,22 +3286,6 @@ int RenderObject::nextOffset(int current) const return current + 1; } -void RenderObject::adjustRectForOutlineAndShadow(LayoutRect& rect) const -{ - int outlineSize = outlineStyleForRepaint()->outlineSize(); - if (const ShadowList* boxShadow = style()->boxShadow()) { - boxShadow->adjustRectForShadow(rect, outlineSize); - return; - } - - rect.inflate(outlineSize); -} - -AnimationController& RenderObject::animation() const -{ - return frame()->animation(); -} - bool RenderObject::isInert() const { const RenderObject* renderer = this; @@ -3148,41 +3294,28 @@ bool RenderObject::isInert() const return renderer->node()->isInert(); } -void RenderObject::imageChanged(ImageResource* image, const IntRect* rect) +// touch-action applies to all elements with both width AND height properties. +// According to the CSS Box Model Spec (http://dev.w3.org/csswg/css-box/#the-width-and-height-properties) +// width applies to all elements but non-replaced inline elements, table rows, and row groups and +// height applies to all elements but non-replaced inline elements, table columns, and column groups. +bool RenderObject::supportsTouchAction() const { - imageChanged(static_cast<WrappedImagePtr>(image), rect); + if (isInline() && !isReplaced()) + return false; + if (isTableRow() || isRenderTableCol()) + return false; + + return true; } -RenderObject* RenderObject::hoverAncestor() const +void RenderObject::imageChanged(ImageResource* image, const IntRect* rect) { - // When searching for the hover ancestor and encountering a named flow thread, - // the search will continue with the DOM ancestor of the top-most element - // in the named flow thread. - // See https://code.google.com/p/chromium/issues/detail?id=243278 - RenderObject* hoverAncestor = parent(); - - // Skip anonymous blocks directly flowed into flow threads as it would - // prevent us from continuing the search on the DOM tree when reaching the named flow thread. - if (hoverAncestor && hoverAncestor->isAnonymousBlock() && hoverAncestor->parent() && hoverAncestor->parent()->isRenderNamedFlowThread()) - hoverAncestor = hoverAncestor->parent(); - - if (hoverAncestor && hoverAncestor->isRenderNamedFlowThread()) { - hoverAncestor = 0; - - Node* node = this->node(); - if (node) { - Node* domAncestorNode = node->parentNode(); - if (domAncestorNode) - hoverAncestor = domAncestorNode->renderer(); - } - } - - return hoverAncestor; + imageChanged(static_cast<WrappedImagePtr>(image), rect); } Element* RenderObject::offsetParent() const { - if (isRoot() || isBody()) + if (isDocumentElement() || isBody()) return 0; if (isOutOfFlowPositioned() && style()->position() == FixedPosition) @@ -3197,10 +3330,6 @@ Element* RenderObject::offsetParent() const for (RenderObject* ancestor = parent(); ancestor; ancestor = ancestor->parent()) { // Spec: http://www.w3.org/TR/cssom-view/#offset-attributes - // CSS regions specification says that region flows should return the body element as their offsetParent. - if (ancestor->isRenderNamedFlowThread()) - return document().body(); - node = ancestor->node(); if (!node) @@ -3209,10 +3338,10 @@ Element* RenderObject::offsetParent() const if (ancestor->isPositioned()) break; - if (node->hasTagName(HTMLNames::bodyTag)) + if (isHTMLBodyElement(*node)) break; - if (!isPositioned() && (isHTMLTableElement(node) || node->hasTagName(tdTag) || node->hasTagName(thTag))) + if (!isPositioned() && (isHTMLTableElement(*node) || isHTMLTableCellElement(*node))) break; // Webkit specific extension where offsetParent stops at zoom level changes. @@ -3329,7 +3458,7 @@ FloatRect RenderObject::strokeBoundingBox() const // Returns the smallest rectangle enclosing all of the painted content // respecting clipping, masking, filters, opacity, stroke-width and markers -FloatRect RenderObject::repaintRectInLocalCoordinates() const +FloatRect RenderObject::paintInvalidationRectInLocalCoordinates() const { ASSERT_NOT_REACHED(); return FloatRect(); @@ -3353,25 +3482,35 @@ bool RenderObject::nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const return false; } -// FIXME: This should really use local coords -// Works on absolute coords - expensive to call -bool RenderObject::isContainedInParentBoundingBox() const +bool RenderObject::isRelayoutBoundaryForInspector() const { - if (!parent()) - return false; + return objectIsRelayoutBoundary(this); +} + +void RenderObject::clearPaintInvalidationState() +{ + setShouldDoFullPaintInvalidationAfterLayout(false); + setShouldDoFullPaintInvalidationIfSelfPaintingLayer(false); + setOnlyNeededPositionedMovementLayout(false); + setShouldInvalidateOverflowForPaint(false); + setLayoutDidGetCalled(false); + setMayNeedPaintInvalidation(false); +} - IntRect parentRect = parent()->absoluteBoundingBoxRect(); - return parentRect.contains(absoluteBoundingBoxRect()); +bool RenderObject::isAllowedToModifyRenderTreeStructure(Document& document) +{ + return DeprecatedDisableModifyRenderTreeStructureAsserts::canModifyRenderTreeStateInAnyState() + || document.lifecycle().stateAllowsRenderTreeMutations(); } -bool RenderObject::isRelayoutBoundaryForInspector() const +DeprecatedDisableModifyRenderTreeStructureAsserts::DeprecatedDisableModifyRenderTreeStructureAsserts() + : m_disabler(gModifyRenderTreeStructureAnyState, true) { - return objectIsRelayoutBoundary(this); } -bool RenderObject::isRenderNamedFlowFragmentContainer() const +bool DeprecatedDisableModifyRenderTreeStructureAsserts::canModifyRenderTreeStateInAnyState() { - return isRenderBlockFlow() && toRenderBlockFlow(this)->renderNamedFlowFragment(); + return gModifyRenderTreeStructureAnyState; } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderObject.h b/chromium/third_party/WebKit/Source/core/rendering/RenderObject.h index 37044c4e86d..11ca5569050 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderObject.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderObject.h @@ -26,48 +26,42 @@ #ifndef RenderObject_h #define RenderObject_h +#include "core/dom/DocumentLifecycle.h" #include "core/dom/Element.h" #include "core/dom/Position.h" #include "core/dom/StyleEngine.h" #include "core/fetch/ImageResourceClient.h" -#include "core/rendering/CompositingState.h" -#include "core/rendering/LayoutIndicator.h" +#include "core/rendering/compositing/CompositingState.h" #include "core/rendering/PaintPhase.h" #include "core/rendering/RenderObjectChildList.h" -#include "core/rendering/ScrollBehavior.h" +#include "core/rendering/ScrollAlignment.h" #include "core/rendering/SubtreeLayoutScope.h" +#include "core/rendering/compositing/CompositingTriggers.h" #include "core/rendering/style/RenderStyle.h" #include "core/rendering/style/StyleInheritedData.h" #include "platform/geometry/FloatQuad.h" #include "platform/geometry/LayoutRect.h" +#include "platform/graphics/CompositingReasons.h" #include "platform/transforms/TransformationMatrix.h" namespace WebCore { class AffineTransform; -class AnimationController; class Cursor; class Document; class HitTestLocation; class HitTestResult; class InlineBox; class InlineFlowBox; -class Path; class Position; class PseudoStyleRequest; class RenderBoxModelObject; -class RenderInline; class RenderBlock; class RenderFlowThread; class RenderGeometryMap; class RenderLayer; class RenderLayerModelObject; -class RenderNamedFlowThread; -class RenderSVGResourceContainer; -class RenderTable; -class RenderTheme; class RenderView; -class ResourceLoadPriorityOptimizer; class TransformState; struct PaintInfo; @@ -113,6 +107,21 @@ enum MapCoordinatesMode { }; typedef unsigned MapCoordinatesFlags; +enum InvalidationReason { + InvalidationIncremental, + InvalidationSelfLayout, + InvalidationBorderFitLines, + InvalidationBorderRadius, + InvalidationBoundsChangeWithBackground, + InvalidationBoundsChange, + InvalidationLocationChange, + InvalidationScroll, + InvalidationSelection, + InvalidationLayer, + InvalidationPaint, + InvalidationPaintRectangle +}; + const int caretWidth = 1; struct AnnotatedRegionValue { @@ -135,10 +144,10 @@ const int showTreeCharacterOffset = 39; class RenderObject : public ImageResourceClient { friend class RenderBlock; friend class RenderBlockFlow; - friend class RenderLayer; // For setParent. friend class RenderLayerReflectionInfo; // For setParent friend class RenderLayerScrollableArea; // For setParent. friend class RenderObjectChildList; + WTF_MAKE_NONCOPYABLE(RenderObject); public: // Anonymous objects should pass the document as their node, and they will then automatically be // marked as anonymous in the constructor. @@ -155,18 +164,13 @@ public: RenderObject* previousSibling() const { return m_previous; } RenderObject* nextSibling() const { return m_next; } - // FIXME: These should be renamed slowFirstChild, slowLastChild, etc. - // to discourage their use. The virtualChildren() call inside these - // can be slow for hot code paths. - // Currently, some subclasses like RenderBlock, override these NON-virtual - // functions to make these fast when we already have a more specific pointer type. - RenderObject* firstChild() const + RenderObject* slowFirstChild() const { if (const RenderObjectChildList* children = virtualChildren()) return children->firstChild(); return 0; } - RenderObject* lastChild() const + RenderObject* slowLastChild() const { if (const RenderObjectChildList* children = virtualChildren()) return children->lastChild(); @@ -213,10 +217,6 @@ public: return locateFlowThreadContainingBlock(); } - RenderNamedFlowThread* renderNamedFlowThreadWrapper() const; - - virtual bool isEmpty() const { return firstChild() == 0; } - #ifndef NDEBUG void setHasAXObject(bool flag) { m_hasAXObject = flag; } bool hasAXObject() const { return m_hasAXObject; } @@ -224,10 +224,10 @@ public: // Helper class forbidding calls to setNeedsLayout() during its lifetime. class SetLayoutNeededForbiddenScope { public: - explicit SetLayoutNeededForbiddenScope(RenderObject*); + explicit SetLayoutNeededForbiddenScope(RenderObject&); ~SetLayoutNeededForbiddenScope(); private: - RenderObject* m_renderObject; + RenderObject& m_renderObject; bool m_preexistingForbidden; }; @@ -291,10 +291,13 @@ private: #endif void addAbsoluteRectForLayer(LayoutRect& result); - void setLayerNeedsFullRepaint(); - void setLayerNeedsFullRepaintForPositionedMovementLayout(); + void setLayerNeedsFullPaintInvalidationForPositionedMovementLayout(); bool requiresAnonymousTableWrappers(const RenderObject*) const; + // Gets pseudoStyle from Shadow host(in case of input elements) + // or from Parent element. + PassRefPtr<RenderStyle> getUncachedPseudoStyleFromParentOrShadowHost() const; + public: #ifndef NDEBUG void showTreeForThis() const; @@ -317,11 +320,10 @@ public: public: bool isPseudoElement() const { return node() && node()->isPseudoElement(); } - virtual bool isBR() const { return false; } virtual bool isBoxModelObject() const { return false; } + virtual bool isBR() const { return false; } + virtual bool isCanvas() const { return false; } virtual bool isCounter() const { return false; } - virtual bool isQuote() const { return false; } - virtual bool isDetailsMarker() const { return false; } virtual bool isEmbeddedObject() const { return false; } virtual bool isFieldset() const { return false; } @@ -339,56 +341,44 @@ public: virtual bool isMenuList() const { return false; } virtual bool isMeter() const { return false; } virtual bool isProgress() const { return false; } + virtual bool isQuote() const { return false; } virtual bool isRenderBlock() const { return false; } virtual bool isRenderBlockFlow() const { return false; } - virtual bool isRenderSVGBlock() const { return false; }; virtual bool isRenderButton() const { return false; } + virtual bool isRenderFlowThread() const { return false; } + virtual bool isRenderFullScreen() const { return false; } + virtual bool isRenderFullScreenPlaceholder() const { return false; } + virtual bool isRenderGrid() const { return false; } virtual bool isRenderIFrame() const { return false; } virtual bool isRenderImage() const { return false; } virtual bool isRenderInline() const { return false; } + virtual bool isRenderMultiColumnSet() const { return false; } virtual bool isRenderPart() const { return false; } virtual bool isRenderRegion() const { return false; } - virtual bool isRenderNamedFlowFragment() const { return false; } + virtual bool isRenderScrollbarPart() const { return false; } + virtual bool isRenderTableCol() const { return false; } virtual bool isRenderView() const { return false; } virtual bool isReplica() const { return false; } - virtual bool isRuby() const { return false; } virtual bool isRubyBase() const { return false; } virtual bool isRubyRun() const { return false; } virtual bool isRubyText() const { return false; } - virtual bool isSlider() const { return false; } virtual bool isSliderThumb() const { return false; } virtual bool isTable() const { return false; } - virtual bool isTableCell() const { return false; } - virtual bool isRenderTableCol() const { return false; } virtual bool isTableCaption() const { return false; } + virtual bool isTableCell() const { return false; } virtual bool isTableRow() const { return false; } virtual bool isTableSection() const { return false; } - virtual bool isTextControl() const { return false; } virtual bool isTextArea() const { return false; } + virtual bool isTextControl() const { return false; } virtual bool isTextField() const { return false; } virtual bool isVideo() const { return false; } virtual bool isWidget() const { return false; } - virtual bool isCanvas() const { return false; } - virtual bool isRenderFullScreen() const { return false; } - virtual bool isRenderFullScreenPlaceholder() const { return false; } - - virtual bool isRenderGrid() const { return false; } - - virtual bool isRenderFlowThread() const { return false; } - virtual bool isRenderNamedFlowThread() const { return false; } - bool isInFlowRenderFlowThread() const { return isRenderFlowThread() && !isOutOfFlowPositioned(); } - bool isOutOfFlowRenderFlowThread() const { return isRenderFlowThread() && isOutOfFlowPositioned(); } - bool isRenderNamedFlowFragmentContainer() const; - - virtual bool isRenderMultiColumnBlock() const { return false; } - virtual bool isRenderMultiColumnSet() const { return false; } - - virtual bool isRenderScrollbarPart() const { return false; } - bool isRoot() const { return document().documentElement() == m_node; } - bool isBody() const; + bool isDocumentElement() const { return document().documentElement() == m_node; } + // isBody is called from RenderBox::styleWillChange and is thus quite hot. + bool isBody() const { return node() && node()->hasTagName(HTMLNames::bodyTag); } bool isHR() const; bool isLegend() const; @@ -413,7 +403,7 @@ public: { m_bitfields.setAncestorLineBoxDirty(value); if (value) - setNeedsLayout(); + setNeedsLayoutAndFullPaintInvalidation(); } enum FlowThreadState { @@ -429,6 +419,7 @@ public: // FIXME: Until all SVG renders can be subclasses of RenderSVGModelObject we have // to add SVG renderer methods to RenderObject with an ASSERT_NOT_REACHED() default implementation. + virtual bool isSVG() const { return false; } virtual bool isSVGRoot() const { return false; } virtual bool isSVGContainer() const { return false; } virtual bool isSVGTransformableContainer() const { return false; } @@ -452,7 +443,6 @@ public: // to inherit from RenderSVGObject -> RenderObject (some need RenderBlock inheritance for instance) virtual void setNeedsTransformUpdate() { } virtual void setNeedsBoundariesUpdate(); - virtual bool needsBoundariesUpdate() { return false; } // Per SVG 1.1 objectBoundingBox ignores clipping, masking, filter effects, opacity and stroke-width. // This is used for all computation of objectBoundingBox relative units and by SVGLocatable::getBBox(). @@ -465,7 +455,7 @@ public: // Returns the smallest rectangle enclosing all of the painted content // respecting clipping, masking, filters, opacity, stroke-width and markers - virtual FloatRect repaintRectInLocalCoordinates() const; + virtual FloatRect paintInvalidationRectInLocalCoordinates() const; // This only returns the transform="" value from the element // most callsites want localToParentTransform() instead. @@ -476,7 +466,7 @@ public: virtual const AffineTransform& localToParentTransform() const; // SVG uses FloatPoint precise hit testing, and passes the point in parent - // coordinates instead of in repaint container coordinates. Eventually the + // coordinates instead of in paint invalidaiton container coordinates. Eventually the // rest of the rendering tree will move to a similar model. virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); @@ -529,8 +519,11 @@ public: }; bool hasBoxDecorations() const { return m_bitfields.boxDecorationState() != NoBoxDecorations; } bool backgroundIsKnownToBeObscured(); - bool borderImageIsLoadedAndCanBeRendered() const; - bool mustRepaintBackgroundOrBorder() const; + bool canRenderBorderImage() const; + bool mustInvalidateBackgroundOrBorderPaintOnWidthChange() const; + bool mustInvalidateBackgroundOrBorderPaintOnHeightChange() const; + bool mustInvalidateFillLayersPaintOnWidthChange(const FillLayer&) const; + bool mustInvalidateFillLayersPaintOnHeightChange(const FillLayer&) const; bool hasBackground() const { return style()->hasBackground(); } bool hasEntirelyFixedBackground() const; @@ -554,6 +547,10 @@ public: bool preferredLogicalWidthsDirty() const { return m_bitfields.preferredLogicalWidthsDirty(); } + bool needsOverflowRecalcAfterStyleChange() const { return m_bitfields.selfNeedsOverflowRecalcAfterStyleChange() || m_bitfields.childNeedsOverflowRecalcAfterStyleChange(); } + bool selfNeedsOverflowRecalcAfterStyleChange() const { return m_bitfields.selfNeedsOverflowRecalcAfterStyleChange(); } + bool childNeedsOverflowRecalcAfterStyleChange() const { return m_bitfields.childNeedsOverflowRecalcAfterStyleChange(); } + bool isSelectionBorder() const; bool hasClip() const { return isOutOfFlowPositioned() && style()->hasClip(); } @@ -569,6 +566,8 @@ public: bool hasBlendMode() const; + bool hasShapeOutside() const { return style() && style()->shapeOutside(); } + inline bool preservesNewline() const; // The pseudo element style can be cached or uncached. Use the cached method if the pseudo element doesn't respect @@ -581,8 +580,7 @@ public: RenderView* view() const { return document().renderView(); }; FrameView* frameView() const { return document().view(); }; - // Returns true if this renderer is rooted, and optionally returns the hosting view (the root of the hierarchy). - bool isRooted(RenderView** = 0) const; + bool isRooted() const; Node* node() const { @@ -591,7 +589,6 @@ public: Node* nonPseudoNode() const { - ASSERT(!LayoutIndicator::inLayout()); return isPseudoElement() ? 0 : node(); } @@ -604,26 +601,26 @@ public: Node* generatingNode() const { return isPseudoElement() ? node()->parentOrShadowHostNode() : node(); } Document& document() const { return m_node->document(); } - Frame* frame() const { return document().frame(); } + LocalFrame* frame() const { return document().frame(); } bool hasOutlineAnnotation() const; bool hasOutline() const { return style()->hasOutline() || hasOutlineAnnotation(); } // Returns the object containing this one. Can be different from parent for positioned elements. - // If repaintContainer and repaintContainerSkipped are not null, on return *repaintContainerSkipped - // is true if the renderer returned is an ancestor of repaintContainer. - RenderObject* container(const RenderLayerModelObject* repaintContainer = 0, bool* repaintContainerSkipped = 0) const; + // If paintInvalidationContainer and paintInvalidationContainerSkipped are not null, on return *paintInvalidationContainerSkipped + // is true if the renderer returned is an ancestor of paintInvalidationContainer. + RenderObject* container(const RenderLayerModelObject* paintInvalidationContainer = 0, bool* paintInvalidationContainerSkipped = 0) const; - virtual RenderObject* hoverAncestor() const; + virtual RenderObject* hoverAncestor() const { return parent(); } Element* offsetParent() const; void markContainingBlocksForLayout(bool scheduleRelayout = true, RenderObject* newRoot = 0, SubtreeLayoutScope* = 0); void setNeedsLayout(MarkingBehavior = MarkContainingBlockChain, SubtreeLayoutScope* = 0); + void setNeedsLayoutAndFullPaintInvalidation(MarkingBehavior = MarkContainingBlockChain, SubtreeLayoutScope* = 0); void clearNeedsLayout(); void setChildNeedsLayout(MarkingBehavior = MarkContainingBlockChain, SubtreeLayoutScope* = 0); void setNeedsPositionedMovementLayout(); - void setNeedsSimplifiedNormalFlowLayout(); void setPreferredLogicalWidthsDirty(MarkingBehavior = MarkContainingBlockChain); void clearPreferredLogicalWidthsDirty(); void invalidateContainerPreferredLogicalWidths(); @@ -633,6 +630,11 @@ public: setNeedsLayout(); setPreferredLogicalWidthsDirty(); } + void setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation() + { + setNeedsLayoutAndFullPaintInvalidation(); + setPreferredLogicalWidthsDirty(); + } void setPositionState(EPosition position) { @@ -665,10 +667,12 @@ public: virtual void paint(PaintInfo&, const LayoutPoint&); - // Recursive function that computes the size and position of this object and all its descendants. - virtual void layout(); - virtual void didLayout(ResourceLoadPriorityOptimizer&); - virtual void didScroll(ResourceLoadPriorityOptimizer&); + // Subclasses must reimplement this method to compute the size and position + // of this object and all its descendants. + virtual void layout() = 0; + virtual bool updateImageLoadingPriorities() { return false; } + void setHasPendingResourceUpdate(bool hasPendingResourceUpdate) { m_bitfields.setHasPendingResourceUpdate(hasPendingResourceUpdate); } + bool hasPendingResourceUpdate() const { return m_bitfields.hasPendingResourceUpdate(); } /* This function performs a layout only if one is needed. */ void layoutIfNeeded() { if (needsLayout()) layout(); } @@ -676,17 +680,15 @@ public: void forceLayout(); void forceChildLayout(); - // True if we can abort layout, leaving a partially laid out tree. - virtual bool supportsPartialLayout() const { return false; } - - // used for element state updates that cannot be fixed with a - // repaint and do not need a relayout + // Used for element state updates that cannot be fixed with a + // paint invalidation and do not need a relayout. virtual void updateFromElement() { } virtual void addAnnotatedRegions(Vector<AnnotatedRegionValue>&); void collectAnnotatedRegions(Vector<AnnotatedRegionValue>&); CompositingState compositingState() const; + virtual CompositingReasons additionalCompositingReasons(CompositingTriggerFlags) const; bool hitTest(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestFilter = HitTestAll); virtual void updateHitTestResult(HitTestResult&, const LayoutPoint&); @@ -698,11 +700,6 @@ public: virtual void dirtyLinesFromChangedChild(RenderObject*); - // Called to update a style that is allowed to trigger animations. - // FIXME: Right now this will typically be called only when updating happens from the DOM on explicit elements. - // We don't yet handle generated content animation such as first-letter or before/after (we'll worry about this later). - void setAnimatableStyle(PassRefPtr<RenderStyle>); - // Set the style of the object and update the state of the object accordingly. void setStyle(PassRefPtr<RenderStyle>); @@ -715,13 +712,10 @@ public: // returns the containing block level element for this element. RenderBlock* containingBlock() const; + RenderObject* clippingContainer() const; bool canContainFixedPositionObjects() const { - return isRenderView() || (hasTransform() && isRenderBlock()) || isSVGForeignObject() || isOutOfFlowRenderFlowThread(); - } - bool canContainAbsolutePositionObjects() const - { return isRenderView() || (hasTransform() && isRenderBlock()) || isSVGForeignObject(); } @@ -739,22 +733,23 @@ public: FloatQuad absoluteToLocalQuad(const FloatQuad&, MapCoordinatesFlags mode = 0) const; // Convert a local quad into the coordinate system of container, taking transforms into account. - FloatQuad localToContainerQuad(const FloatQuad&, const RenderLayerModelObject* repaintContainer, MapCoordinatesFlags = 0, bool* wasFixed = 0) const; - FloatPoint localToContainerPoint(const FloatPoint&, const RenderLayerModelObject* repaintContainer, MapCoordinatesFlags = 0, bool* wasFixed = 0) const; + FloatQuad localToContainerQuad(const FloatQuad&, const RenderLayerModelObject* paintInvalidatinoContainer, MapCoordinatesFlags = 0, bool* wasFixed = 0) const; + FloatPoint localToContainerPoint(const FloatPoint&, const RenderLayerModelObject* paintInvalidationContainer, MapCoordinatesFlags = 0, bool* wasFixed = 0) const; // Return the offset from the container() renderer (excluding transforms). In multi-column layout, // different offsets apply at different points, so return the offset that applies to the given point. - virtual LayoutSize offsetFromContainer(RenderObject*, const LayoutPoint&, bool* offsetDependsOnPoint = 0) const; + virtual LayoutSize offsetFromContainer(const RenderObject*, const LayoutPoint&, bool* offsetDependsOnPoint = 0) const; // Return the offset from an object up the container() chain. Asserts that none of the intermediate objects have transforms. - LayoutSize offsetFromAncestorContainer(RenderObject*) const; + LayoutSize offsetFromAncestorContainer(const RenderObject*) const; virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint&) const { } - // FIXME: useTransforms should go away eventually - IntRect absoluteBoundingBoxRect(bool useTransform = true) const; - IntRect absoluteBoundingBoxRectIgnoringTransforms() const { return absoluteBoundingBoxRect(false); } + // Computes the position of the given render object in the space of |repaintContainer|. + LayoutPoint positionFromPaintInvalidationContainer(const RenderLayerModelObject* paintInvalidationContainer) const; - bool isContainedInParentBoundingBox() const; + IntRect absoluteBoundingBoxRect() const; + // FIXME: This function should go away eventually + IntRect absoluteBoundingBoxRectIgnoringTransforms() const; // Build an array of quads in absolute coords for line boxes virtual void absoluteQuads(Vector<FloatQuad>&, bool* /*wasFixed*/ = 0) const { } @@ -783,79 +778,91 @@ public: return style()->visitedDependentColor(colorProperty); } - inline Color resolveColor(int colorProperty, Color fallback) const - { - Color color = resolveColor(colorProperty); - return color.isValid() ? color : fallback; - } - - inline Color resolveColor(Color color) const - { - return color; - } - // Used only by Element::pseudoStyleCacheIsInvalid to get a first line style based off of a // given new style, without accessing the cache. PassRefPtr<RenderStyle> uncachedFirstLineStyle(RenderStyle*) const; // Anonymous blocks that are part of of a continuation chain will return their inline continuation's outline style instead. - // This is typically only relevant when repainting. - virtual RenderStyle* outlineStyleForRepaint() const { return style(); } + // This is typically only relevant when invalidating paints. + virtual RenderStyle* outlineStyleForPaintInvalidation() const { return style(); } virtual CursorDirective getCursor(const LayoutPoint&, Cursor&) const; - void getTextDecorationColors(unsigned decorations, Color& underline, Color& overline, Color& linethrough, bool quirksMode = false, bool firstlineStyle = false); + struct AppliedTextDecoration { + Color color; + TextDecorationStyle style; + AppliedTextDecoration() : color(Color::transparent), style(TextDecorationStyleSolid) { } + }; + + void getTextDecorations(unsigned decorations, AppliedTextDecoration& underline, AppliedTextDecoration& overline, AppliedTextDecoration& linethrough, bool quirksMode = false, bool firstlineStyle = false); // Return the RenderLayerModelObject in the container chain which is responsible for painting this object, or 0 - // if painting is root-relative. This is the container that should be passed to the 'forRepaint' + // if painting is root-relative. This is the container that should be passed to the 'forPaintInvalidation' // methods. - RenderLayerModelObject* containerForRepaint() const; - // Actually do the repaint of rect r for this object which has been computed in the coordinate space - // of repaintContainer. If repaintContainer is 0, repaint via the view. - void repaintUsingContainer(const RenderLayerModelObject* repaintContainer, const IntRect&) const; + const RenderLayerModelObject* containerForPaintInvalidation() const; + const RenderLayerModelObject* enclosingCompositedContainer() const; + const RenderLayerModelObject* adjustCompositedContainerForSpecialAncestors(const RenderLayerModelObject* paintInvalidationContainer) const; + bool isPaintInvalidationContainer() const; + + LayoutRect computePaintInvalidationRect() + { + return computePaintInvalidationRect(containerForPaintInvalidation()); + } + + // Returns the paint invalidation rect for this RenderObject in the coordinate space of the paint backing (typically a GraphicsLayer) for |paintInvalidationContainer|. + LayoutRect computePaintInvalidationRect(const RenderLayerModelObject* paintInvalidationContainer) const; + + // Returns the rect bounds needed to invalidate the paint of this object, in the coordinate space of the rendering backing of |paintInvalidationContainer| + LayoutRect boundsRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const; - // Repaint the entire object. Called when, e.g., the color of a border changes, or when a border + // Actually do the paint invalidate of rect r for this object which has been computed in the coordinate space + // of the GraphicsLayer backing of |paintInvalidationContainer|. Note that this coordinaten space is not the same + // as the local coordinate space of |paintInvalidationContainer| in the presence of layer squashing. + // If |paintInvalidationContainer| is 0, invalidate paints via the view. + // FIXME: |paintInvalidationContainer| should never be 0. See crbug.com/363699. + void invalidatePaintUsingContainer(const RenderLayerModelObject* paintInvalidationContainer, const IntRect&, InvalidationReason) const; + + // Invalidate the paint of the entire object. Called when, e.g., the color of a border changes, or when a border // style changes. - void repaint() const; + void paintInvalidationForWholeRenderer() const; + + // Invalidate the paint of a specific subrectangle within a given object. The rect |r| is in the object's coordinate space. + void invalidatePaintRectangle(const LayoutRect&) const; - // Repaint a specific subrectangle within a given object. The rect |r| is in the object's coordinate space. - void repaintRectangle(const LayoutRect&) const; + // Invalidate the paint only if our old bounds and new bounds are different. The caller may pass in newBounds if they are known. + bool invalidatePaintAfterLayoutIfNeeded(const RenderLayerModelObject* paintInvalidationContainer, bool wasSelfLayout, + const LayoutRect& oldBounds, const LayoutPoint& oldPositionFromPaintInvalidationContainer, + const LayoutRect* newBoundsPtr = 0, const LayoutPoint* newPositionFromPaintInvalidationContainer = 0); - // Repaint only if our old bounds and new bounds are different. The caller may pass in newBounds and newOutlineBox if they are known. - bool repaintAfterLayoutIfNeeded(const RenderLayerModelObject* repaintContainer, bool wasSelfLayout, - const LayoutRect& oldBounds, const LayoutRect& oldOutlineBox, const LayoutRect* newBoundsPtr = 0, const LayoutRect* newOutlineBoxPtr = 0); + // Walk the tree after layout issuing paint invalidations for renderers that have changed or moved, updating bounds that have changed, and clearing paint invalidation state. + virtual void invalidateTreeAfterLayout(const RenderLayerModelObject&); - virtual void repaintOverflow(); + virtual void invalidatePaintForOverflow(); + void invalidatePaintForOverflowIfNeeded(); - bool checkForRepaintDuringLayout() const; + bool checkForPaintInvalidation() const; + bool checkForPaintInvalidationDuringLayout() const; - // Returns the rect that should be repainted whenever this object changes. The rect is in the view's - // coordinate space. This method deals with outlines and overflow. + // Returns the rect that should have paint invalidated whenever this object changes. The rect is in the view's + // coordinate space. This method deals with outlines and overflow. LayoutRect absoluteClippedOverflowRect() const { - return clippedOverflowRectForRepaint(0); + return clippedOverflowRectForPaintInvalidation(0); } IntRect pixelSnappedAbsoluteClippedOverflowRect() const; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const; - virtual LayoutRect rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const; - virtual LayoutRect outlineBoundsForRepaint(const RenderLayerModelObject* /*repaintContainer*/, const RenderGeometryMap* = 0) const { return LayoutRect(); } - - // Given a rect in the object's coordinate space, compute a rect suitable for repainting - // that rect in the coordinate space of repaintContainer. - virtual void computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect&, bool fixed = false) const; - virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed = false) const; - - // If multiple-column layout results in applying an offset to the given point, add the same - // offset to the given size. - virtual void adjustForColumns(LayoutSize&, const LayoutPoint&) const { } - LayoutSize offsetForColumns(const LayoutPoint& point) const - { - LayoutSize offset; - adjustForColumns(offset, point); - return offset; - } + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const; + virtual LayoutRect rectWithOutlineForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, LayoutUnit outlineWidth) const; - virtual unsigned int length() const { return 1; } + // Given a rect in the object's coordinate space, compute a rect suitable for invalidating paints of + // that rect in the coordinate space of paintInvalidationContainer. + virtual void mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect&, bool fixed = false) const; + virtual void computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect& paintInvalidationRect, bool fixed = false) const; + + // Return the offset to the column in which the specified point (in flow-thread coordinates) + // lives. This is used to convert a flow-thread point to a visual point. + virtual LayoutSize columnOffset(const LayoutPoint&) const { return LayoutSize(); } + + virtual unsigned length() const { return 1; } bool isFloatingOrOutOfFlowPositioned() const { return (isFloating() || isOutOfFlowPositioned()); } @@ -864,9 +871,6 @@ 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. - int maximalOutlineSize(PaintPhase) const; - enum SelectionState { SelectionNone, // The object is not selected. SelectionStart, // The object either contains the start of a selection run or is the start of a run @@ -884,8 +888,8 @@ public: // A single rectangle that encompasses all of the selected objects within this object. Used to determine the tightest // possible bounding box for the selection. - LayoutRect selectionRect(bool clipToVisibleContent = true) { return selectionRectForRepaint(0, clipToVisibleContent); } - virtual LayoutRect selectionRectForRepaint(const RenderLayerModelObject* /*repaintContainer*/, bool /*clipToVisibleContent*/ = true) { return LayoutRect(); } + LayoutRect selectionRect(bool clipToVisibleContent = true) { return selectionRectForPaintInvalidation(0, clipToVisibleContent); } + virtual LayoutRect selectionRectForPaintInvalidation(const RenderLayerModelObject* /*paintInvalidationContainer*/, bool /*clipToVisibleContent*/ = true) { return LayoutRect(); } virtual bool canBeSelectionLeaf() const { return false; } bool hasSelectedChildren() const { return selectionState() != SelectionNone; } @@ -916,7 +920,6 @@ public: // Virtual function helpers for the deprecated Flexible Box Layout (display: -webkit-box). virtual bool isDeprecatedFlexibleBox() const { return false; } - virtual bool isStretchingChildren() const { return false; } // Virtual function helper for the new FlexibleBox Layout (display: -webkit-flex). virtual bool isFlexibleBox() const { return false; } @@ -935,23 +938,25 @@ public: virtual int previousOffsetForBackwardDeletion(int current) const; virtual int nextOffset(int current) const; - virtual void imageChanged(ImageResource*, const IntRect* = 0); + virtual void imageChanged(ImageResource*, const IntRect* = 0) OVERRIDE FINAL; virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) { } - virtual bool willRenderImage(ImageResource*); + virtual bool willRenderImage(ImageResource*) OVERRIDE FINAL; void selectionStartEnd(int& spos, int& epos) const; void remove() { if (parent()) parent()->removeChild(this); } - AnimationController& animation() const; - bool isInert() const; + + bool supportsTouchAction() const; + bool visibleToHitTestRequest(const HitTestRequest& request) const { return style()->visibility() == VISIBLE && (request.ignorePointerEventsNone() || style()->pointerEvents() != PE_NONE) && !isInert(); } + bool visibleToHitTesting() const { return style()->visibility() == VISIBLE && style()->pointerEvents() != PE_NONE && !isInert(); } // 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(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const; + virtual void mapLocalToContainer(const RenderLayerModelObject* paintInvalidationContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const; virtual void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const; // Pushes state onto RenderGeometryMap about how to map coordinates from this renderer to its container, or ancestorToStopAt (whichever is encountered first). @@ -968,49 +973,64 @@ public: // Compute a list of hit-test rectangles per layer rooted at this renderer. virtual void computeLayerHitTestRects(LayerHitTestRects&) const; - LayoutRect absoluteOutlineBounds() const - { - return outlineBoundsForRepaint(0); - } - - // 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. + // Return the renderer whose background style is used to paint the root background. Should only be called on the renderer for which isDocumentElement() is true. RenderObject* rendererForRootBackground(); RespectImageOrientationEnum shouldRespectImageOrientation() const; bool isRelayoutBoundaryForInspector() const; - const LayoutRect& newRepaintRect() const { return m_newRepaintRect; } - void setNewRepaintRect(const LayoutRect& rect) { m_newRepaintRect = rect; } + const LayoutRect& previousPaintInvalidationRect() const { return m_previousPaintInvalidationRect; } + void setPreviousPaintInvalidationRect(const LayoutRect& rect) { m_previousPaintInvalidationRect = rect; } - const LayoutRect& oldRepaintRect() const { return m_oldRepaintRect; } - void setOldRepaintRect(const LayoutRect& rect) { m_oldRepaintRect = rect; } + const LayoutPoint& previousPositionFromPaintInvalidationContainer() const { return m_previousPositionFromPaintInvalidationContainer; } + void setPreviousPositionFromPaintInvalidationContainer(const LayoutPoint& location) { m_previousPositionFromPaintInvalidationContainer = location; } - bool shouldDoFullRepaintAfterLayout() const { return m_bitfields.shouldDoFullRepaintAfterLayout(); } - void setShouldDoFullRepaintAfterLayout(bool b) { m_bitfields.setShouldDoFullRepaintAfterLayout(b); } - bool shouldRepaintOverflowIfNeeded() const { return m_bitfields.shouldRepaintOverflowIfNeeded(); } + bool shouldDoFullPaintInvalidationAfterLayout() const { return m_bitfields.shouldDoFullPaintInvalidationAfterLayout(); } + void setShouldDoFullPaintInvalidationAfterLayout(bool b) { m_bitfields.setShouldDoFullPaintInvalidationAfterLayout(b); } + bool shouldInvalidateOverflowForPaint() const { return m_bitfields.shouldInvalidateOverflowForPaint(); } - void clearRepaintRects() - { - setNewRepaintRect(LayoutRect()); - setOldRepaintRect(LayoutRect()); + bool shouldDoFullPaintInvalidationIfSelfPaintingLayer() const { return m_bitfields.shouldDoFullPaintInvalidationIfSelfPaintingLayer(); } + void setShouldDoFullPaintInvalidationIfSelfPaintingLayer(bool b) { m_bitfields.setShouldDoFullPaintInvalidationIfSelfPaintingLayer(b); } - setShouldDoFullRepaintAfterLayout(false); - setShouldRepaintOverflowIfNeeded(false); - setLayoutDidGetCalled(false); - } + bool onlyNeededPositionedMovementLayout() const { return m_bitfields.onlyNeededPositionedMovementLayout(); } + void setOnlyNeededPositionedMovementLayout(bool b) { m_bitfields.setOnlyNeededPositionedMovementLayout(b); } + + void clearPaintInvalidationState(); // layoutDidGetCalled indicates whether this render object was re-laid-out // since the last call to setLayoutDidGetCalled(false) on this object. bool layoutDidGetCalled() { return m_bitfields.layoutDidGetCalled(); } void setLayoutDidGetCalled(bool b) { m_bitfields.setLayoutDidGetCalled(b); } + bool mayNeedPaintInvalidation() { return m_bitfields.mayNeedPaintInvalidation(); } + void setMayNeedPaintInvalidation(bool b) + { + m_bitfields.setMayNeedPaintInvalidation(b); + + // Make sure our parent is marked as needing invalidation. + if (b && parent() && !parent()->mayNeedPaintInvalidation()) + parent()->setMayNeedPaintInvalidation(b); + } + + bool shouldCheckForPaintInvalidationAfterLayout() + { + return layoutDidGetCalled() || mayNeedPaintInvalidation(); + } + + bool supportsLayoutStateCachedOffsets() const { return !hasColumns() && !hasTransform() && !hasReflection() && !style()->isFlippedBlocksWritingMode(); } + + void setNeedsOverflowRecalcAfterStyleChange(); + void markContainingBlocksForOverflowRecalc(); + protected: inline bool layerCreationAllowedForSubtree() const; - // Overrides should call the superclass at the end - virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); - // Overrides should call the superclass at the start + // Overrides should call the superclass at the end. m_style will be 0 the first time + // this function will be called. + virtual void styleWillChange(StyleDifference, const RenderStyle& newStyle); + // Overrides should call the superclass at the start. |oldStyle| will be 0 the first + // time this function is called. virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); void propagateStyleToAnonymousChildren(bool blockChildrenOnly = false); @@ -1028,11 +1048,10 @@ protected: void paintFocusRing(PaintInfo&, const LayoutPoint&, RenderStyle*); void paintOutline(PaintInfo&, const LayoutRect&); void addPDFURLRect(GraphicsContext*, const LayoutRect&); + void addChildFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer); virtual LayoutRect viewRect() const; - void adjustRectForOutlineAndShadow(LayoutRect&) const; - void clearLayoutRootIfNeeded() const; virtual void willBeDestroyed(); void postDestroy(); @@ -1057,13 +1076,12 @@ protected: virtual void computeSelfHitTestRects(Vector<LayoutRect>&, const LayoutPoint& layerOffset) const { }; private: - RenderBlock* containerForFixedPosition(const RenderLayerModelObject* repaintContainer = 0, bool* repaintContainerSkipped = 0) const; + RenderBlock* containerForFixedPosition(const RenderLayerModelObject* paintInvalidationContainer = 0, bool* paintInvalidationContainerSkipped = 0) const; RenderFlowThread* locateFlowThreadContainingBlock() const; void removeFromRenderFlowThread(); void removeFromRenderFlowThreadRecursive(RenderFlowThread*); - bool shouldRepaintForStyleDifference(StyleDifference) const; bool hasImmediateNonWhitespaceTextChildOrPropertiesDependentOnColor() const; RenderStyle* cachedFirstLineStyle() const; @@ -1075,8 +1093,10 @@ private: #ifndef NDEBUG void checkBlockPositionedObjectsNeedLayout(); - void checkNotInPartialLayout(); #endif + const char* invalidationReasonToString(InvalidationReason) const; + + static bool isAllowedToModifyRenderTreeStructure(Document&); RefPtr<RenderStyle> m_style; @@ -1109,18 +1129,25 @@ private: public: RenderObjectBitfields(Node* node) : m_selfNeedsLayout(false) - // FIXME: shouldDoFullRepaintAfterLayout is needed because we reset - // the layout bits before repaint when doing repaintAfterLayout. - // Holding the layout bits until after repaint would remove the need + // FIXME: shouldDoFullPaintInvalidationAfterLayout is needed because we reset + // the layout bits beforeissing paint invalidations when doing invalidateTreeAfterLayout. + // Holding the layout bits until after paint invalidation would remove the need // for this flag. - , m_shouldDoFullRepaintAfterLayout(false) - , m_shouldRepaintOverflowIfNeeded(false) + , m_shouldDoFullPaintInvalidationAfterLayout(false) + , m_shouldInvalidateOverflowForPaint(false) + , m_shouldDoFullPaintInvalidationIfSelfPaintingLayer(false) + // FIXME: We should remove mayNeedPaintInvalidation once we are able to + // use the other layout flags to detect the same cases. crbug.com/370118 + , m_mayNeedPaintInvalidation(false) + , m_onlyNeededPositionedMovementLayout(false) , m_needsPositionedMovementLayout(false) , m_normalChildNeedsLayout(false) , m_posChildNeedsLayout(false) , m_needsSimplifiedNormalFlowLayout(false) , m_preferredLogicalWidthsDirty(false) , m_floating(false) + , m_selfNeedsOverflowRecalcAfterStyleChange(false) + , m_childNeedsOverflowRecalcAfterStyleChange(false) , m_isAnonymous(!node) , m_isText(false) , m_isBox(false) @@ -1142,19 +1169,25 @@ private: , m_selectionState(SelectionNone) , m_flowThreadState(NotInsideFlowThread) , m_boxDecorationState(NoBoxDecorations) + , m_hasPendingResourceUpdate(false) { } - // 32 bits have been used in the first word, and 2 in the second. + // 32 bits have been used in the first word, and 6 in the second. ADD_BOOLEAN_BITFIELD(selfNeedsLayout, SelfNeedsLayout); - ADD_BOOLEAN_BITFIELD(shouldDoFullRepaintAfterLayout, ShouldDoFullRepaintAfterLayout); - ADD_BOOLEAN_BITFIELD(shouldRepaintOverflowIfNeeded, ShouldRepaintOverflowIfNeeded); + ADD_BOOLEAN_BITFIELD(shouldDoFullPaintInvalidationAfterLayout, ShouldDoFullPaintInvalidationAfterLayout); + ADD_BOOLEAN_BITFIELD(shouldInvalidateOverflowForPaint, ShouldInvalidateOverflowForPaint); + ADD_BOOLEAN_BITFIELD(shouldDoFullPaintInvalidationIfSelfPaintingLayer, ShouldDoFullPaintInvalidationIfSelfPaintingLayer); + ADD_BOOLEAN_BITFIELD(mayNeedPaintInvalidation, MayNeedPaintInvalidation); + ADD_BOOLEAN_BITFIELD(onlyNeededPositionedMovementLayout, OnlyNeededPositionedMovementLayout); ADD_BOOLEAN_BITFIELD(needsPositionedMovementLayout, NeedsPositionedMovementLayout); ADD_BOOLEAN_BITFIELD(normalChildNeedsLayout, NormalChildNeedsLayout); ADD_BOOLEAN_BITFIELD(posChildNeedsLayout, PosChildNeedsLayout); ADD_BOOLEAN_BITFIELD(needsSimplifiedNormalFlowLayout, NeedsSimplifiedNormalFlowLayout); ADD_BOOLEAN_BITFIELD(preferredLogicalWidthsDirty, PreferredLogicalWidthsDirty); ADD_BOOLEAN_BITFIELD(floating, Floating); + ADD_BOOLEAN_BITFIELD(selfNeedsOverflowRecalcAfterStyleChange, SelfNeedsOverflowRecalcAfterStyleChange); + ADD_BOOLEAN_BITFIELD(childNeedsOverflowRecalcAfterStyleChange, ChildNeedsOverflowRecalcAfterStyleChange); ADD_BOOLEAN_BITFIELD(isAnonymous, IsAnonymous); ADD_BOOLEAN_BITFIELD(isText, IsText); @@ -1186,6 +1219,9 @@ private: unsigned m_boxDecorationState : 2; // BoxDecorationState public: + + ADD_BOOLEAN_BITFIELD(hasPendingResourceUpdate, HasPendingResourceUpdate); + bool isOutOfFlowPositioned() const { return m_positionedState == IsOutOfFlowPositioned; } bool isRelPositioned() const { return m_positionedState == IsRelativelyPositioned; } bool isStickyPositioned() const { return m_positionedState == IsStickyPositioned; } @@ -1219,19 +1255,40 @@ private: void setNeedsSimplifiedNormalFlowLayout(bool b) { m_bitfields.setNeedsSimplifiedNormalFlowLayout(b); } void setIsDragging(bool b) { m_bitfields.setIsDragging(b); } void setEverHadLayout(bool b) { m_bitfields.setEverHadLayout(b); } - void setShouldRepaintOverflowIfNeeded(bool b) { m_bitfields.setShouldRepaintOverflowIfNeeded(b); } + void setShouldInvalidateOverflowForPaint(bool b) { m_bitfields.setShouldInvalidateOverflowForPaint(b); } + void setSelfNeedsOverflowRecalcAfterStyleChange(bool b) { m_bitfields.setSelfNeedsOverflowRecalcAfterStyleChange(b); } + void setChildNeedsOverflowRecalcAfterStyleChange(bool b) { m_bitfields.setChildNeedsOverflowRecalcAfterStyleChange(b); } private: // Store state between styleWillChange and styleDidChange static bool s_affectsParentBlock; - LayoutRect m_oldRepaintRect; - LayoutRect m_newRepaintRect; + // This stores the paint invalidation rect from the previous layout. + LayoutRect m_previousPaintInvalidationRect; + + // This stores the position in the paint invalidation container's coordinate. + // It is used to detect renderer shifts that forces a full invalidation. + LayoutPoint m_previousPositionFromPaintInvalidationContainer; +}; + +// FIXME: remove this once the render object lifecycle ASSERTS are no longer hit. +class DeprecatedDisableModifyRenderTreeStructureAsserts { + WTF_MAKE_NONCOPYABLE(DeprecatedDisableModifyRenderTreeStructureAsserts); +public: + DeprecatedDisableModifyRenderTreeStructureAsserts(); + + static bool canModifyRenderTreeStateInAnyState(); + +private: + TemporaryChange<bool> m_disabler; }; +// Allow equality comparisons of RenderObjects by reference or pointer, interchangeably. +DEFINE_COMPARISON_OPERATORS_WITH_REFERENCES(RenderObject) + inline bool RenderObject::documentBeingDestroyed() const { - return !document().renderer(); + return document().lifecycle().state() >= DocumentLifecycle::Stopping; } inline bool RenderObject::isBeforeContent() const @@ -1259,27 +1316,30 @@ inline bool RenderObject::isBeforeOrAfterContent() const return isBeforeContent() || isAfterContent(); } +// If repaintAfterLayout is enabled, setNeedsLayout() won't cause full paint invalidations as +// setNeedsLayoutAndFullPaintInvalidation() does. Otherwise the two methods are identical. inline void RenderObject::setNeedsLayout(MarkingBehavior markParents, SubtreeLayoutScope* layouter) { -#ifndef NDEBUG - checkNotInPartialLayout(); -#endif ASSERT(!isSetNeedsLayoutForbidden()); bool alreadyNeededLayout = m_bitfields.selfNeedsLayout(); setSelfNeedsLayout(true); if (!alreadyNeededLayout) { if (markParents == MarkContainingBlockChain && (!layouter || layouter->root() != this)) markContainingBlocksForLayout(true, 0, layouter); - if (hasLayer()) - setLayerNeedsFullRepaint(); } } +inline void RenderObject::setNeedsLayoutAndFullPaintInvalidation(MarkingBehavior markParents, SubtreeLayoutScope* layouter) +{ + setNeedsLayout(markParents, layouter); + setShouldDoFullPaintInvalidationAfterLayout(true); +} + inline void RenderObject::clearNeedsLayout() { -#ifndef NDEBUG - checkNotInPartialLayout(); -#endif + if (needsPositionedMovementLayoutOnly()) + setOnlyNeededPositionedMovementLayout(true); + setLayoutDidGetCalled(true); setSelfNeedsLayout(false); setEverHadLayout(true); setPosChildNeedsLayout(false); @@ -1310,19 +1370,7 @@ inline void RenderObject::setNeedsPositionedMovementLayout() if (!alreadyNeededLayout) { markContainingBlocksForLayout(); if (hasLayer()) - setLayerNeedsFullRepaintForPositionedMovementLayout(); - } -} - -inline void RenderObject::setNeedsSimplifiedNormalFlowLayout() -{ - bool alreadyNeededLayout = needsSimplifiedNormalFlowLayout(); - setNeedsSimplifiedNormalFlowLayout(true); - ASSERT(!isSetNeedsLayoutForbidden()); - if (!alreadyNeededLayout) { - markContainingBlocksForLayout(); - if (hasLayer()) - setLayerNeedsFullRepaint(); + setLayerNeedsFullPaintInvalidationForPositionedMovementLayout(); } } @@ -1392,6 +1440,12 @@ inline int adjustForAbsoluteZoom(int value, RenderObject* renderer) return adjustForAbsoluteZoom(value, renderer->style()); } +inline double adjustDoubleForAbsoluteZoom(double value, RenderObject& renderer) +{ + ASSERT(renderer.style()); + return adjustDoubleForAbsoluteZoom(value, *renderer.style()); +} + inline LayoutUnit adjustLayoutUnitForAbsoluteZoom(LayoutUnit value, RenderObject& renderer) { ASSERT(renderer.style()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderObjectChildList.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderObjectChildList.cpp index 80cee464c7d..6fd0358266b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderObjectChildList.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderObjectChildList.cpp @@ -56,16 +56,21 @@ RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, Render if (oldChild->isFloatingOrOutOfFlowPositioned()) toRenderBox(oldChild)->removeFloatingOrPositionedChildFromBlockLists(); - // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or - // that a positioned child got yanked). We also repaint, so that the area exposed when the child - // disappears gets repainted properly. - if (!owner->documentBeingDestroyed() && notifyRenderer && oldChild->everHadLayout()) { - oldChild->setNeedsLayoutAndPrefWidthsRecalc(); - // We only repaint |oldChild| if we have a RenderLayer as its visual overflow may not be tracked by its parent. - if (oldChild->isBody()) - owner->view()->repaint(); - else - oldChild->repaint(); + { + // FIXME: We should not be allowing repaint during layout. crbug.com/336250 + AllowPaintInvalidationScope scoper(owner->frameView()); + + // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or + // that a positioned child got yanked). We also repaint, so that the area exposed when the child + // disappears gets repainted properly. + if (!owner->documentBeingDestroyed() && notifyRenderer && oldChild->everHadLayout()) { + oldChild->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); + // We only repaint |oldChild| if we have a RenderLayer as its visual overflow may not be tracked by its parent. + if (oldChild->isBody()) + owner->view()->paintInvalidationForWholeRenderer(); + else + oldChild->paintInvalidationForWholeRenderer(); + } } // If we have a line box wrapper, delete it. @@ -153,7 +158,7 @@ void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* n RenderCounter::rendererSubtreeAttached(newChild); } - newChild->setNeedsLayoutAndPrefWidthsRecalc(); + newChild->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); if (!owner->normalChildNeedsLayout()) owner->setChildNeedsLayout(); // We may supply the static position for an absolute positioned child. diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderOverflow.h b/chromium/third_party/WebKit/Source/core/rendering/RenderOverflow.h index 2a965c7037a..2860b7cf848 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderOverflow.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderOverflow.h @@ -50,16 +50,6 @@ public: const LayoutRect visualOverflowRect() const { return m_visualOverflow; } LayoutRect contentsVisualOverflowRect() const { return m_contentsVisualOverflow; } - void setMinYLayoutOverflow(LayoutUnit overflow) { m_layoutOverflow.setY(overflow); } - void setMaxYLayoutOverflow(LayoutUnit overflow) { m_layoutOverflow.setHeight(overflow - m_layoutOverflow.y()); } - void setMinXLayoutOverflow(LayoutUnit overflow) { m_layoutOverflow.setX(overflow); } - void setMaxXLayoutOverflow(LayoutUnit overflow) { m_layoutOverflow.setWidth(overflow - m_layoutOverflow.x()); } - - void setMinYVisualOverflow(LayoutUnit overflow) { m_visualOverflow.setY(overflow); } - void setMaxYVisualOverflow(LayoutUnit overflow) { m_visualOverflow.setHeight(overflow - m_layoutOverflow.y()); } - void setMinXVisualOverflow(LayoutUnit overflow) { m_visualOverflow.setX(overflow); } - void setMaxXVisualOverflow(LayoutUnit overflow) { m_visualOverflow.setWidth(overflow - m_layoutOverflow.x()); } - void move(LayoutUnit dx, LayoutUnit dy); void addLayoutOverflow(const LayoutRect&); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderPart.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderPart.cpp index c0cbf957881..408a6453598 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderPart.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderPart.cpp @@ -25,8 +25,8 @@ #include "config.h" #include "core/rendering/RenderPart.h" -#include "core/frame/Frame.h" #include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/html/HTMLFrameElementBase.h" #include "core/plugins/PluginView.h" #include "core/rendering/HitTestResult.h" @@ -46,31 +46,14 @@ RenderPart::RenderPart(Element* node) RenderPart::~RenderPart() { - clearWidget(); } -void RenderPart::setWidget(PassRefPtr<Widget> widget) +LayerType RenderPart::layerTypeRequired() const { - if (widget == this->widget()) - return; - - RenderWidget::setWidget(widget); - - // make sure the scrollbars are set correctly for restore - // ### find better fix - viewCleared(); -} - -void RenderPart::viewCleared() -{ -} - -bool RenderPart::requiresLayer() const -{ - if (RenderWidget::requiresLayer()) - return true; - - return requiresAcceleratedCompositing(); + LayerType type = RenderWidget::layerTypeRequired(); + if (type != NoLayer) + return type; + return ForcedLayer; } bool RenderPart::requiresAcceleratedCompositing() const @@ -104,18 +87,15 @@ bool RenderPart::needsPreferredWidthsRecalculation() const return embeddedContentBox(); } -RenderBox* RenderPart::embeddedContentBox() const -{ - if (!node() || !widget() || !widget()->isFrameView()) - return 0; - return toFrameView(widget())->embeddedContentBox(); -} - bool RenderPart::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) { if (!widget() || !widget()->isFrameView() || !request.allowsChildFrameContent()) return RenderWidget::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action); + // FIXME: Until RemoteFrames use RemoteFrameViews, we need an explicit check here. + if (toFrameView(widget())->frame().isRemoteFrameTemporary()) + return RenderWidget::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action); + FrameView* childFrameView = toFrameView(widget()); RenderView* childRoot = childFrameView->renderView(); @@ -149,4 +129,11 @@ bool RenderPart::nodeAtPoint(const HitTestRequest& request, HitTestResult& resul return RenderWidget::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action); } +CompositingReasons RenderPart::additionalCompositingReasons(CompositingTriggerFlags) const +{ + if (requiresAcceleratedCompositing()) + return CompositingReasonIFrame; + return CompositingReasonNone; +} + } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderPart.h b/chromium/third_party/WebKit/Source/core/rendering/RenderPart.h index f26a7e242c5..f0a1699740c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderPart.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderPart.h @@ -33,22 +33,20 @@ public: explicit RenderPart(Element*); virtual ~RenderPart(); - virtual void setWidget(PassRefPtr<Widget>) OVERRIDE FINAL; - virtual void viewCleared(); - bool requiresAcceleratedCompositing() const; virtual bool needsPreferredWidthsRecalculation() const OVERRIDE FINAL; - virtual RenderBox* embeddedContentBox() const OVERRIDE FINAL; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; protected: - virtual bool requiresLayer() const; + virtual LayerType layerTypeRequired() const OVERRIDE; private: virtual bool isRenderPart() const OVERRIDE FINAL { return true; } - virtual const char* renderName() const { return "RenderPart"; } + virtual const char* renderName() const OVERRIDE { return "RenderPart"; } + + virtual CompositingReasons additionalCompositingReasons(CompositingTriggerFlags) const OVERRIDE; }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderPart, isRenderPart()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderProgress.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderProgress.cpp index 9bf99a86a3d..b3d994d6c3c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderProgress.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderProgress.cpp @@ -54,8 +54,8 @@ void RenderProgress::updateFromElement() m_position = element->position(); updateAnimationState(); - repaint(); - RenderBlock::updateFromElement(); + paintInvalidationForWholeRenderer(); + RenderBlockFlow::updateFromElement(); } double RenderProgress::animationProgress() const @@ -71,9 +71,9 @@ bool RenderProgress::isDeterminate() const void RenderProgress::animationTimerFired(Timer<RenderProgress>*) { - repaint(); + paintInvalidationForWholeRenderer(); if (!m_animationTimer.isActive() && m_animating) - m_animationTimer.startOneShot(m_animationRepeatInterval); + m_animationTimer.startOneShot(m_animationRepeatInterval, FROM_HERE); } void RenderProgress::updateAnimationState() @@ -88,7 +88,7 @@ void RenderProgress::updateAnimationState() m_animating = animating; if (m_animating) { m_animationStartTime = currentTime(); - m_animationTimer.startOneShot(m_animationRepeatInterval); + m_animationTimer.startOneShot(m_animationRepeatInterval, FROM_HERE); } else m_animationTimer.stop(); } @@ -98,7 +98,7 @@ HTMLProgressElement* RenderProgress::progressElement() const if (!node()) return 0; - if (isHTMLProgressElement(node())) + if (isHTMLProgressElement(*node())) return toHTMLProgressElement(node()); ASSERT(node()->shadowHost()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderProgress.h b/chromium/third_party/WebKit/Source/core/rendering/RenderProgress.h index bd1cac97f15..18d5c5d3e9f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderProgress.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderProgress.h @@ -37,14 +37,13 @@ public: double animationStartTime() const { return m_animationStartTime; } bool isDeterminate() const; - virtual void updateFromElement(); + virtual void updateFromElement() OVERRIDE; HTMLProgressElement* progressElement() const; private: - virtual const char* renderName() const { return "RenderProgress"; } - virtual bool isProgress() const { return true; } - virtual bool supportsPartialLayout() const OVERRIDE { return false; } + virtual const char* renderName() const OVERRIDE { return "RenderProgress"; } + virtual bool isProgress() const OVERRIDE { return true; } void animationTimerFired(Timer<RenderProgress>*); void updateAnimationState(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderRegion.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderRegion.cpp index 0614d3aade2..864f98807e9 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderRegion.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderRegion.cpp @@ -34,8 +34,7 @@ #include "core/rendering/FlowThreadController.h" #include "core/rendering/HitTestLocation.h" #include "core/rendering/PaintInfo.h" -#include "core/rendering/RenderBoxRegionInfo.h" -#include "core/rendering/RenderNamedFlowThread.h" +#include "core/rendering/RenderFlowThread.h" #include "core/rendering/RenderView.h" using namespace std; @@ -45,11 +44,7 @@ namespace WebCore { RenderRegion::RenderRegion(Element* element, RenderFlowThread* flowThread) : RenderBlockFlow(element) , m_flowThread(flowThread) - , m_parentNamedFlowThread(0) - , m_computedAutoHeight(-1) , m_isValid(false) - , m_hasCustomRegionStyle(false) - , m_hasAutoLogicalHeight(false) { } @@ -62,29 +57,12 @@ LayoutUnit RenderRegion::pageLogicalWidth() const LayoutUnit RenderRegion::pageLogicalHeight() const { ASSERT(m_flowThread); - if (hasComputedAutoHeight() && !m_flowThread->inConstrainedLayoutPhase()) { - ASSERT(hasAutoLogicalHeight()); - return computedAutoHeight(); - } return m_flowThread->isHorizontalWritingMode() ? contentHeight() : contentWidth(); } -// This method returns the maximum page size of a region with auto-height. This is the initial -// height value for auto-height regions in the first layout phase of the parent named flow. -LayoutUnit RenderRegion::maxPageLogicalHeight() const -{ - ASSERT(m_flowThread); - ASSERT(hasAutoLogicalHeight() && !m_flowThread->inConstrainedLayoutPhase()); - return style()->logicalMaxHeight().isUndefined() ? RenderFlowThread::maxLogicalHeight() : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight()); -} - LayoutUnit RenderRegion::logicalHeightOfAllFlowThreadContent() const { ASSERT(m_flowThread); - if (hasComputedAutoHeight() && !m_flowThread->inConstrainedLayoutPhase()) { - ASSERT(hasAutoLogicalHeight()); - return computedAutoHeight(); - } return m_flowThread->isHorizontalWritingMode() ? contentHeight() : contentWidth(); } @@ -97,54 +75,30 @@ LayoutRect RenderRegion::overflowRectForFlowThreadPortion(const LayoutRect& flow { ASSERT(isValid()); - bool isLastRegionWithRegionFragmentBreak = (isLastPortion && (style()->regionFragment() == BreakRegionFragment)); - if (hasOverflowClip() || isLastRegionWithRegionFragmentBreak) + if (hasOverflowClip()) return flowThreadPortionRect; LayoutRect flowThreadOverflow = m_flowThread->visualOverflowRect(); // Only clip along the flow thread axis. - LayoutUnit outlineSize = maximalOutlineSize(PaintPhaseOutline); LayoutRect clipRect; if (m_flowThread->isHorizontalWritingMode()) { - LayoutUnit minY = isFirstPortion ? (flowThreadOverflow.y() - outlineSize) : flowThreadPortionRect.y(); - LayoutUnit maxY = isLastPortion ? max(flowThreadPortionRect.maxY(), flowThreadOverflow.maxY()) + outlineSize : flowThreadPortionRect.maxY(); - bool clipX = style()->overflowX() != OVISIBLE; - LayoutUnit minX = clipX ? flowThreadPortionRect.x() : min(flowThreadPortionRect.x(), flowThreadOverflow.x() - outlineSize); - LayoutUnit maxX = clipX ? flowThreadPortionRect.maxX() : max(flowThreadPortionRect.maxX(), (flowThreadOverflow.maxX() + outlineSize)); + LayoutUnit minY = isFirstPortion ? flowThreadOverflow.y() : flowThreadPortionRect.y(); + LayoutUnit maxY = isLastPortion ? max(flowThreadPortionRect.maxY(), flowThreadOverflow.maxY()) : flowThreadPortionRect.maxY(); + LayoutUnit minX = min(flowThreadPortionRect.x(), flowThreadOverflow.x()); + LayoutUnit maxX = max(flowThreadPortionRect.maxX(), flowThreadOverflow.maxX()); clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); } else { - LayoutUnit minX = isFirstPortion ? (flowThreadOverflow.x() - outlineSize) : flowThreadPortionRect.x(); - LayoutUnit maxX = isLastPortion ? max(flowThreadPortionRect.maxX(), flowThreadOverflow.maxX()) + outlineSize : flowThreadPortionRect.maxX(); - bool clipY = style()->overflowY() != OVISIBLE; - LayoutUnit minY = clipY ? flowThreadPortionRect.y() : min(flowThreadPortionRect.y(), (flowThreadOverflow.y() - outlineSize)); - LayoutUnit maxY = clipY ? flowThreadPortionRect.maxY() : max(flowThreadPortionRect.y(), (flowThreadOverflow.maxY() + outlineSize)); + LayoutUnit minX = isFirstPortion ? flowThreadOverflow.x() : flowThreadPortionRect.x(); + LayoutUnit maxX = isLastPortion ? max(flowThreadPortionRect.maxX(), flowThreadOverflow.maxX()) : flowThreadPortionRect.maxX(); + LayoutUnit minY = min(flowThreadPortionRect.y(), (flowThreadOverflow.y())); + LayoutUnit maxY = max(flowThreadPortionRect.y(), (flowThreadOverflow.maxY())); clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); } return clipRect; } -RegionOversetState RenderRegion::regionOversetState() const -{ - if (isValid() && element()) - return element()->regionOversetState(); - - return RegionUndefined; -} - -void RenderRegion::setRegionOversetState(RegionOversetState state) -{ - if (element()) - element()->setRegionOversetState(state); -} - -Element* RenderRegion::element() const -{ - ASSERT(nodeForRegion() && nodeForRegion()->isElementNode()); - return toElement(nodeForRegion()); -} - LayoutUnit RenderRegion::pageLogicalTopForOffset(LayoutUnit /* offset */) const { return flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().y() : flowThreadPortionRect().x(); @@ -164,148 +118,10 @@ bool RenderRegion::isLastRegion() const return m_flowThread->lastRegion() == this; } -static bool shouldPaintRegionContentsInPhase(PaintPhase phase) -{ - return phase == PaintPhaseForeground - || phase == PaintPhaseSelection - || phase == PaintPhaseTextClip; -} - -void RenderRegion::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset) -{ - if (style()->visibility() != VISIBLE) - return; - - RenderBlock::paintObject(paintInfo, paintOffset); - - if (!isValid()) - return; - - // Delegate painting of content in region to RenderFlowThread. - // RenderFlowThread is a self painting layer (being a positioned object) who is painting its children, the collected objects. - // Since we do not want to paint the flow thread content multiple times (for each painting phase of the region object), - // we allow the flow thread painting only in certain phases. - if (!shouldPaintRegionContentsInPhase(paintInfo.phase)) - return; - - setRegionObjectsRegionStyle(); - m_flowThread->paintFlowThreadPortionInRegion(paintInfo, this, flowThreadPortionRect(), flowThreadPortionOverflowRect(), LayoutPoint(paintOffset.x() + borderLeft() + paddingLeft(), paintOffset.y() + borderTop() + paddingTop())); - restoreRegionObjectsOriginalStyle(); -} - -// Hit Testing -bool RenderRegion::hitTestFlowThreadContents(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) -{ - if (!isValid() || action != HitTestForeground) - return false; - - LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region()); - boundsRect.moveBy(accumulatedOffset); - if (visibleToHitTesting() && locationInContainer.intersects(boundsRect)) { - if (m_flowThread->hitTestFlowThreadPortionInRegion(this, flowThreadPortionRect(), flowThreadPortionOverflowRect(), request, result, - locationInContainer, LayoutPoint(accumulatedOffset.x() + borderLeft() + paddingLeft(), accumulatedOffset.y() + borderTop() + paddingTop()))) - return true; - } - - return false; -} - -void RenderRegion::checkRegionStyle() -{ - ASSERT(m_flowThread); - bool customRegionStyle = false; - - // FIXME: Region styling doesn't work for pseudo elements. - if (isElementBasedRegion()) - customRegionStyle = view()->document().ensureStyleResolver().checkRegionStyle(this->element()); - - setHasCustomRegionStyle(customRegionStyle); - m_flowThread->checkRegionsWithStyling(); -} - -void RenderRegion::incrementAutoLogicalHeightCount() -{ - ASSERT(isValid()); - ASSERT(m_hasAutoLogicalHeight); - - m_flowThread->incrementAutoLogicalHeightRegions(); -} - -void RenderRegion::decrementAutoLogicalHeightCount() -{ - ASSERT(isValid()); - - m_flowThread->decrementAutoLogicalHeightRegions(); -} - -void RenderRegion::updateRegionHasAutoLogicalHeightFlag() -{ - ASSERT(m_flowThread); - - if (!isValid()) - return; - - bool didHaveAutoLogicalHeight = m_hasAutoLogicalHeight; - m_hasAutoLogicalHeight = shouldHaveAutoLogicalHeight(); - if (m_hasAutoLogicalHeight != didHaveAutoLogicalHeight) { - if (m_hasAutoLogicalHeight) { - incrementAutoLogicalHeightCount(); - } else { - clearComputedAutoHeight(); - decrementAutoLogicalHeightCount(); - } - } -} - -bool RenderRegion::shouldHaveAutoLogicalHeight() const -{ - bool hasSpecifiedEndpointsForHeight = style()->logicalTop().isSpecified() && style()->logicalBottom().isSpecified(); - bool hasAnchoredEndpointsForHeight = isOutOfFlowPositioned() && hasSpecifiedEndpointsForHeight; - bool hasAutoHeightStyle = style()->logicalHeight().isAuto() || style()->logicalHeight().isFitContent() - || style()->logicalHeight().isMaxContent() || style()->logicalHeight().isMinContent(); - return hasAutoHeightStyle && !hasAnchoredEndpointsForHeight; -} - -void RenderRegion::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) -{ - RenderBlock::styleDidChange(diff, oldStyle); - - // If the region is not attached to any thread, there is no need to check - // whether the region has region styling since no content will be displayed - // into the region. - if (!m_flowThread) { - setHasCustomRegionStyle(false); - return; - } - - checkRegionStyle(); - updateRegionHasAutoLogicalHeightFlag(); - - if (oldStyle && oldStyle->writingMode() != style()->writingMode()) - m_flowThread->regionChangedWritingMode(this); -} - -void RenderRegion::layoutBlock(bool relayoutChildren, LayoutUnit) +void RenderRegion::layoutBlock(bool relayoutChildren) { RenderBlockFlow::layoutBlock(relayoutChildren); - if (isValid()) { - LayoutRect oldRegionRect(flowThreadPortionRect()); - if (!isHorizontalWritingMode()) - oldRegionRect = oldRegionRect.transposedRect(); - - if (hasAutoLogicalHeight() && !m_flowThread->inConstrainedLayoutPhase()) { - m_flowThread->invalidateRegions(); - clearComputedAutoHeight(); - return; - } - - if (!isRenderRegionSet() && (oldRegionRect.width() != pageLogicalWidth() || oldRegionRect.height() != pageLogicalHeight())) { - // This can happen even if we are in the inConstrainedLayoutPhase and it will trigger a pathological layout of the flow thread. - m_flowThread->invalidateRegions(); - } - } - // FIXME: We need to find a way to set up overflow properly. Our flow thread hasn't gotten a layout // yet, so we can't look to it for correct information. It's possible we could wait until after the RenderFlowThread // gets a layout, and then try to propagate overflow information back to the region, and then mark for a second layout. @@ -314,8 +130,6 @@ void RenderRegion::layoutBlock(bool relayoutChildren, LayoutUnit) // The big problem though is that overflow needs to be region-specific. We can't simply use the RenderFlowThread's global // overflow values, since then we'd always think any narrow region had huge overflow (all the way to the width of the // RenderFlowThread itself). - // - // We'll need to expand RenderBoxRegionInfo to also hold left and right overflow values. } void RenderRegion::repaintFlowThreadContent(const LayoutRect& repaintRect) const @@ -345,30 +159,7 @@ void RenderRegion::repaintFlowThreadContentRectangle(const LayoutRect& repaintRe flipForWritingMode(clippedRect); // Issue the repaint. - repaintRectangle(clippedRect); -} - -void RenderRegion::installFlowThread() -{ - ASSERT(view()); - - m_flowThread = view()->flowThreadController()->ensureRenderFlowThreadWithName(style()->regionThread()); - - // By now the flow thread should already be added to the rendering tree, - // 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_parentNamedFlowThread = 0; - for ( ; parentObject; parentObject = parentObject->parent()) { - 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_parentNamedFlowThread) - m_flowThread = 0; - break; - } - } + invalidatePaintRectangle(clippedRect); } void RenderRegion::attachRegion() @@ -379,72 +170,19 @@ void RenderRegion::attachRegion() // A region starts off invalid. setIsValid(false); - // Initialize the flow thread reference and create the flow thread object if needed. - // The flow thread lifetime is influenced by the number of regions attached to it, - // and we are attaching the region to the flow thread. - installFlowThread(); - if (!m_flowThread) return; // Only after adding the region to the thread, the region is marked to be valid. m_flowThread->addRegionToThread(this); - - // The region just got attached to the flow thread, lets check whether - // it has region styling rules associated. - checkRegionStyle(); - - if (!isValid()) - return; - - m_hasAutoLogicalHeight = shouldHaveAutoLogicalHeight(); - if (hasAutoLogicalHeight()) - incrementAutoLogicalHeightCount(); } void RenderRegion::detachRegion() { if (m_flowThread) { m_flowThread->removeRegionFromThread(this); - if (hasAutoLogicalHeight()) - decrementAutoLogicalHeightCount(); + m_flowThread = 0; } - m_flowThread = 0; -} - -RenderBoxRegionInfo* RenderRegion::renderBoxRegionInfo(const RenderBox* box) const -{ - ASSERT(isValid()); - return m_renderBoxRegionInfo.get(box); -} - -RenderBoxRegionInfo* RenderRegion::setRenderBoxRegionInfo(const RenderBox* box, LayoutUnit logicalLeftInset, LayoutUnit logicalRightInset, - bool containingBlockChainIsInset) -{ - ASSERT(isValid()); - - OwnPtr<RenderBoxRegionInfo>& boxInfo = m_renderBoxRegionInfo.add(box, nullptr).iterator->value; - if (boxInfo) - *boxInfo = RenderBoxRegionInfo(logicalLeftInset, logicalRightInset, containingBlockChainIsInset); - else - boxInfo = adoptPtr(new RenderBoxRegionInfo(logicalLeftInset, logicalRightInset, containingBlockChainIsInset)); - - return boxInfo.get(); -} - -PassOwnPtr<RenderBoxRegionInfo> RenderRegion::takeRenderBoxRegionInfo(const RenderBox* box) -{ - return m_renderBoxRegionInfo.take(box); -} - -void RenderRegion::removeRenderBoxRegionInfo(const RenderBox* box) -{ - m_renderBoxRegionInfo.remove(box); -} - -void RenderRegion::deleteAllRenderBoxRegionInfo() -{ - m_renderBoxRegionInfo.clear(); } LayoutUnit RenderRegion::logicalTopOfFlowThreadContentRect(const LayoutRect& rect) const @@ -459,167 +197,24 @@ LayoutUnit RenderRegion::logicalBottomOfFlowThreadContentRect(const LayoutRect& return flowThread()->isHorizontalWritingMode() ? rect.maxY() : rect.maxX(); } -void RenderRegion::setRegionObjectsRegionStyle() -{ - if (!hasCustomRegionStyle()) - return; - - // Start from content nodes and recursively compute the style in region for the render objects below. - // If the style in region was already computed, used that style instead of computing a new one. - RenderNamedFlowThread* namedFlow = view()->flowThreadController()->ensureRenderFlowThreadWithName(style()->regionThread()); - const NamedFlowContentNodes& contentNodes = namedFlow->contentNodes(); - - for (NamedFlowContentNodes::const_iterator iter = contentNodes.begin(), end = contentNodes.end(); iter != end; ++iter) { - const Node* node = *iter; - // The list of content nodes contains also the nodes with display:none. - if (!node->renderer()) - continue; - - RenderObject* object = node->renderer(); - // If the content node does not flow any of its children in this region, - // we do not compute any style for them in this region. - if (!flowThread()->objectInFlowRegion(object, this)) - continue; - - // If the object has style in region, use that instead of computing a new one. - RenderObjectRegionStyleMap::iterator it = m_renderObjectRegionStyle.find(object); - RefPtr<RenderStyle> objectStyleInRegion; - bool objectRegionStyleCached = false; - if (it != m_renderObjectRegionStyle.end()) { - objectStyleInRegion = it->value.style; - ASSERT(it->value.cached); - objectRegionStyleCached = true; - } else { - objectStyleInRegion = computeStyleInRegion(object); - } - - setObjectStyleInRegion(object, objectStyleInRegion, objectRegionStyleCached); - - computeChildrenStyleInRegion(object); - } -} - -void RenderRegion::restoreRegionObjectsOriginalStyle() -{ - if (!hasCustomRegionStyle()) - return; - - RenderObjectRegionStyleMap temp; - for (RenderObjectRegionStyleMap::iterator iter = m_renderObjectRegionStyle.begin(), end = m_renderObjectRegionStyle.end(); iter != end; ++iter) { - RenderObject* object = const_cast<RenderObject*>(iter->key); - RefPtr<RenderStyle> objectRegionStyle = object->style(); - RefPtr<RenderStyle> objectOriginalStyle = iter->value.style; - object->setStyleInternal(objectOriginalStyle); - - bool shouldCacheRegionStyle = iter->value.cached; - if (!shouldCacheRegionStyle) { - // Check whether we should cache the computed style in region. - unsigned changedContextSensitiveProperties = ContextSensitivePropertyNone; - StyleDifference styleDiff = objectOriginalStyle->diff(objectRegionStyle.get(), changedContextSensitiveProperties); - if (styleDiff < StyleDifferenceLayoutPositionedMovementOnly) - shouldCacheRegionStyle = true; - } - if (shouldCacheRegionStyle) { - ObjectRegionStyleInfo styleInfo; - styleInfo.style = objectRegionStyle; - styleInfo.cached = true; - temp.set(object, styleInfo); - } - } - - m_renderObjectRegionStyle.swap(temp); -} - void RenderRegion::insertedIntoTree() { - RenderBlock::insertedIntoTree(); + RenderBlockFlow::insertedIntoTree(); attachRegion(); } void RenderRegion::willBeRemovedFromTree() { - RenderBlock::willBeRemovedFromTree(); + RenderBlockFlow::willBeRemovedFromTree(); detachRegion(); } -PassRefPtr<RenderStyle> RenderRegion::computeStyleInRegion(const RenderObject* object) -{ - ASSERT(object); - ASSERT(object->view()); - ASSERT(!object->isAnonymous()); - ASSERT(object->node() && object->node()->isElementNode()); - - // FIXME: Region styling fails for pseudo-elements because the renderers don't have a node. - Element* element = toElement(object->node()); - RefPtr<RenderStyle> renderObjectRegionStyle = object->view()->document().ensureStyleResolver().styleForElement(element, 0, DisallowStyleSharing, MatchAllRules, this); - - return renderObjectRegionStyle.release(); -} - -void RenderRegion::computeChildrenStyleInRegion(const RenderObject* object) -{ - for (RenderObject* child = object->lastChild(); child; child = child->previousSibling()) { - - RenderObjectRegionStyleMap::iterator it = m_renderObjectRegionStyle.find(child); - - RefPtr<RenderStyle> childStyleInRegion; - bool objectRegionStyleCached = false; - if (it != m_renderObjectRegionStyle.end()) { - childStyleInRegion = it->value.style; - objectRegionStyleCached = true; - } else { - if (child->isAnonymous() || child->isInFlowRenderFlowThread()) - childStyleInRegion = RenderStyle::createAnonymousStyleWithDisplay(object->style(), child->style()->display()); - else if (child->isText()) - childStyleInRegion = RenderStyle::clone(object->style()); - else - childStyleInRegion = computeStyleInRegion(child); - } - - setObjectStyleInRegion(child, childStyleInRegion, objectRegionStyleCached); - - computeChildrenStyleInRegion(child); - } -} - -void RenderRegion::setObjectStyleInRegion(RenderObject* object, PassRefPtr<RenderStyle> styleInRegion, bool objectRegionStyleCached) -{ - ASSERT(object->flowThreadContainingBlock()); - - RefPtr<RenderStyle> objectOriginalStyle = object->style(); - object->setStyleInternal(styleInRegion); - - if (object->isBoxModelObject() && !object->hasBoxDecorations()) { - bool hasBoxDecorations = object->isTableCell() - || object->style()->hasBackground() - || object->style()->hasBorder() - || object->style()->hasAppearance() - || object->style()->boxShadow(); - object->setHasBoxDecorations(hasBoxDecorations); - } - - ObjectRegionStyleInfo styleInfo; - styleInfo.style = objectOriginalStyle; - styleInfo.cached = objectRegionStyleCached; - m_renderObjectRegionStyle.set(object, styleInfo); -} - -void RenderRegion::clearObjectStyleInRegion(const RenderObject* object) -{ - ASSERT(object); - m_renderObjectRegionStyle.remove(object); - - // Clear the style for the children of this object. - for (RenderObject* child = object->lastChild(); child; child = child->previousSibling()) - clearObjectStyleInRegion(child); -} - void RenderRegion::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const { if (!isValid()) { - RenderBlock::computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth); + RenderBlockFlow::computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth); return; } @@ -627,62 +222,4 @@ void RenderRegion::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, La maxLogicalWidth = m_flowThread->maxPreferredLogicalWidth(); } -void RenderRegion::getRanges(Vector<RefPtr<Range> >& rangeObjects) const -{ - RenderNamedFlowThread* namedFlow = view()->flowThreadController()->ensureRenderFlowThreadWithName(style()->regionThread()); - namedFlow->getRanges(rangeObjects, this); -} - -void RenderRegion::updateLogicalHeight() -{ - RenderBlock::updateLogicalHeight(); - - if (!hasAutoLogicalHeight()) - return; - - // We want to update the logical height based on the computed auto-height - // only if the view is in the layout phase in which all the - // auto logical height regions have a computed auto-height. - if (!m_flowThread->inConstrainedLayoutPhase()) - return; - - // There may be regions with auto logical height that during the prerequisite layout phase - // did not have the chance to layout flow thread content. Because of that, these regions do not - // have a computedAutoHeight and they will not be able to fragment any flow - // thread content. - if (!hasComputedAutoHeight()) - return; - - LayoutUnit autoHeight = hasOverrideHeight() ? overrideLogicalContentHeight() : computedAutoHeight(); - - LayoutUnit newLogicalHeight = autoHeight + borderAndPaddingLogicalHeight(); - ASSERT(newLogicalHeight < RenderFlowThread::maxLogicalHeight()); - if (newLogicalHeight > logicalHeight()) { - setLogicalHeight(newLogicalHeight); - // Recalculate position of the render block after new logical height is set. - // (needed in absolute positioning case with bottom alignment for example) - RenderBlock::updateLogicalHeight(); - } -} - -Node* RenderRegion::nodeForRegion() const -{ - if (parent() && isRenderNamedFlowFragment()) - return parent()->node(); - return node(); -} - -Node* RenderRegion::generatingNodeForRegion() const -{ - if (parent() && isRenderNamedFlowFragment()) - return parent()->generatingNode(); - return generatingNode(); -} - -bool RenderRegion::isElementBasedRegion() const -{ - Node* node = nodeForRegion(); - return node && node->isElementNode() && !node->isPseudoElement(); -} - } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderRegion.h b/chromium/third_party/WebKit/Source/core/rendering/RenderRegion.h index c05d61359b2..d1a134c6b5f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderRegion.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderRegion.h @@ -37,20 +37,13 @@ namespace WebCore { struct LayerFragment; typedef Vector<LayerFragment, 1> LayerFragments; -class RenderBox; -class RenderBoxRegionInfo; class RenderFlowThread; -class RenderNamedFlowThread; class RenderRegion : public RenderBlockFlow { public: explicit RenderRegion(Element*, RenderFlowThread*); - virtual bool isRenderRegion() const OVERRIDE { return true; } - - bool hitTestFlowThreadContents(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction); - - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; + virtual bool isRenderRegion() const OVERRIDE FINAL { return true; } void setFlowThreadPortionRect(const LayoutRect& rect) { m_flowThreadPortionRect = rect; } LayoutRect flowThreadPortionRect() const { return m_flowThreadPortionRect; } @@ -59,167 +52,64 @@ public: void attachRegion(); void detachRegion(); - RenderNamedFlowThread* parentNamedFlowThread() const { return m_parentNamedFlowThread; } RenderFlowThread* flowThread() const { return m_flowThread; } // Valid regions do not create circular dependencies with other flows. bool isValid() const { return m_isValid; } void setIsValid(bool valid) { m_isValid = valid; } - bool hasCustomRegionStyle() const { return m_hasCustomRegionStyle; } - void setHasCustomRegionStyle(bool hasCustomRegionStyle) { m_hasCustomRegionStyle = hasCustomRegionStyle; } - - RenderBoxRegionInfo* renderBoxRegionInfo(const RenderBox*) const; - RenderBoxRegionInfo* setRenderBoxRegionInfo(const RenderBox*, LayoutUnit logicalLeftInset, LayoutUnit logicalRightInset, - bool containingBlockChainIsInset); - PassOwnPtr<RenderBoxRegionInfo> takeRenderBoxRegionInfo(const RenderBox*); - void removeRenderBoxRegionInfo(const RenderBox*); - - void deleteAllRenderBoxRegionInfo(); - bool isFirstRegion() const; bool isLastRegion() const; - void clearObjectStyleInRegion(const RenderObject*); - - RegionOversetState regionOversetState() const; - void setRegionOversetState(RegionOversetState); - - // These methods represent the width and height of a "page" and for a RenderRegion they are just the - // content width and content height of a region. For RenderRegionSets, however, they will be the width and - // height of a single column or page in the set. + // These methods represent the width and height of a "page" and for a RenderRegion they are just + // the content width and content height of a region. For RenderMultiColumnSets, however, they + // will be the width and height of a single column or page in the set. virtual LayoutUnit pageLogicalWidth() const; virtual LayoutUnit pageLogicalHeight() const; - virtual LayoutUnit maxPageLogicalHeight() const; LayoutUnit logicalTopOfFlowThreadContentRect(const LayoutRect&) const; LayoutUnit logicalBottomOfFlowThreadContentRect(const LayoutRect&) const; LayoutUnit logicalTopForFlowThreadContent() const { return logicalTopOfFlowThreadContentRect(flowThreadPortionRect()); }; LayoutUnit logicalBottomForFlowThreadContent() const { return logicalBottomOfFlowThreadContentRect(flowThreadPortionRect()); }; - void getRanges(Vector<RefPtr<Range> >&) const; - // This method represents the logical height of the entire flow thread portion used by the region or set. // For RenderRegions it matches logicalPaginationHeight(), but for sets it is the height of all the pages // or columns added together. virtual LayoutUnit logicalHeightOfAllFlowThreadContent() const; - bool hasAutoLogicalHeight() const { return m_hasAutoLogicalHeight; } - - const LayoutUnit& computedAutoHeight() const - { - ASSERT(hasComputedAutoHeight()); - return m_computedAutoHeight; - } - - void setComputedAutoHeight(LayoutUnit computedAutoHeight) - { - ASSERT(computedAutoHeight >= 0); - m_computedAutoHeight = computedAutoHeight; - } - - void clearComputedAutoHeight() - { - m_computedAutoHeight = -1; - } - - bool hasComputedAutoHeight() const { return (m_computedAutoHeight >= 0); } - // The top of the nearest page inside the region. For RenderRegions, this is just the logical top of the // flow thread portion we contain. For sets, we have to figure out the top of the nearest column or // page. virtual LayoutUnit pageLogicalTopForOffset(LayoutUnit offset) const; - virtual void expandToEncompassFlowThreadContentsIfNeeded() { }; - - // Whether or not this region is a set. - virtual bool isRenderRegionSet() const { return false; } - virtual void repaintFlowThreadContent(const LayoutRect& repaintRect) const; virtual void collectLayerFragments(LayerFragments&, const LayoutRect&, const LayoutRect&) { } - virtual bool canHaveChildren() const OVERRIDE { return false; } - virtual bool canHaveGeneratedChildren() const OVERRIDE { return true; } - - bool isElementBasedRegion() const; - - Node* nodeForRegion() const; - Node* generatingNodeForRegion() const; + virtual bool canHaveChildren() const OVERRIDE FINAL { return false; } + virtual bool canHaveGeneratedChildren() const OVERRIDE FINAL { return true; } virtual const char* renderName() const OVERRIDE { return "RenderRegion"; } protected: - void setRegionObjectsRegionStyle(); - void restoreRegionObjectsOriginalStyle(); - - virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE; + virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE FINAL; LayoutRect overflowRectForFlowThreadPortion(const LayoutRect& flowThreadPortionRect, bool isFirstPortion, bool isLastPortion) const; void repaintFlowThreadContentRectangle(const LayoutRect& repaintRect, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const LayoutPoint& regionLocation) const; - virtual bool shouldHaveAutoLogicalHeight() const; - private: - virtual void insertedIntoTree() OVERRIDE; - virtual void willBeRemovedFromTree() OVERRIDE; - - virtual void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0) OVERRIDE; - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - virtual void paintObject(PaintInfo&, const LayoutPoint&) OVERRIDE; - - virtual void updateLogicalHeight() OVERRIDE; + virtual void insertedIntoTree() OVERRIDE FINAL; + virtual void willBeRemovedFromTree() OVERRIDE FINAL; - virtual void installFlowThread(); - - PassRefPtr<RenderStyle> computeStyleInRegion(const RenderObject*); - void computeChildrenStyleInRegion(const RenderObject*); - void setObjectStyleInRegion(RenderObject*, PassRefPtr<RenderStyle>, bool objectRegionStyleCached); - - void checkRegionStyle(); - void updateRegionHasAutoLogicalHeightFlag(); - - void incrementAutoLogicalHeightCount(); - void decrementAutoLogicalHeightCount(); - - Element* element() const; + virtual void layoutBlock(bool relayoutChildren) OVERRIDE FINAL; protected: RenderFlowThread* m_flowThread; private: - // 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. - RenderNamedFlowThread* m_parentNamedFlowThread; LayoutRect m_flowThreadPortionRect; - - // This map holds unique information about a block that is split across regions. - // A RenderBoxRegionInfo* tells us about any layout information for a RenderBox that - // is unique to the region. For now it just holds logical width information for RenderBlocks, but eventually - // it will also hold a custom style for any box (for region styling). - typedef HashMap<const RenderBox*, OwnPtr<RenderBoxRegionInfo> > RenderBoxRegionInfoMap; - RenderBoxRegionInfoMap m_renderBoxRegionInfo; - - struct ObjectRegionStyleInfo { - // Used to store the original style of the object in region - // so that the original style is properly restored after paint. - // Also used to store computed style of the object in region between - // region paintings, so that the style in region is computed only - // when necessary. - RefPtr<RenderStyle> style; - // True if the computed style in region is cached. - bool cached; - }; - typedef HashMap<const RenderObject*, ObjectRegionStyleInfo > RenderObjectRegionStyleMap; - RenderObjectRegionStyleMap m_renderObjectRegionStyle; - - LayoutUnit m_computedAutoHeight; - bool m_isValid : 1; - bool m_hasCustomRegionStyle : 1; - bool m_hasAutoLogicalHeight : 1; }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderRegion, isRenderRegion()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderRegionSet.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderRegionSet.cpp deleted file mode 100644 index 933611547d9..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderRegionSet.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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 "core/rendering/RenderRegionSet.h" - -#include "core/rendering/RenderFlowThread.h" - -namespace WebCore { - -RenderRegionSet::RenderRegionSet(Element* element, RenderFlowThread* flowThread) - : RenderRegion(element, flowThread) -{ -} - -void RenderRegionSet::installFlowThread() -{ - // We don't have to do anything, since we were able to connect the flow thread - // in the constructor. -} - -void RenderRegionSet::expandToEncompassFlowThreadContentsIfNeeded() -{ - // Whenever the last region is a set, it always expands its region rect to consume all - // of the flow thread content. This is because it is always capable of generating an - // infinite number of boxes in order to hold all of the remaining content. - LayoutRect rect(flowThreadPortionRect()); - - // Get the offset within the flow thread in its block progression direction. Then get the - // flow thread's remaining logical height including its overflow and expand our rect - // to encompass that remaining height and overflow. The idea is that we will generate - // additional columns and pages to hold that overflow, since people do write bad - // content like <body style="height:0px"> in multi-column layouts. - bool isHorizontal = flowThread()->isHorizontalWritingMode(); - LayoutUnit logicalTopOffset = isHorizontal ? rect.y() : rect.x(); - LayoutRect layoutRect = flowThread()->layoutOverflowRect(); - LayoutUnit logicalHeightWithOverflow = (isHorizontal ? layoutRect.maxY() : layoutRect.maxX()) - logicalTopOffset; - setFlowThreadPortionRect(LayoutRect(rect.x(), rect.y(), isHorizontal ? rect.width() : logicalHeightWithOverflow, isHorizontal ? logicalHeightWithOverflow : rect.height())); -} - -} diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderRegionSet.h b/chromium/third_party/WebKit/Source/core/rendering/RenderRegionSet.h deleted file mode 100644 index 6802852d0be..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderRegionSet.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 "core/rendering/RenderBoxRegionInfo.h" -#include "core/rendering/RenderRegion.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(Element*, RenderFlowThread*); - -protected: - virtual bool shouldHaveAutoLogicalHeight() const OVERRIDE { return false; } - -private: - virtual void installFlowThread() OVERRIDE FINAL; - - virtual void expandToEncompassFlowThreadContentsIfNeeded() OVERRIDE FINAL; - - virtual const char* renderName() const = 0; - - virtual bool isRenderRegionSet() const OVERRIDE FINAL { return true; } -}; - -} // namespace WebCore - -#endif // RenderRegionSet_h - diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderReplaced.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderReplaced.cpp index 059cd205f57..89970827847 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderReplaced.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderReplaced.cpp @@ -24,14 +24,14 @@ #include "config.h" #include "core/rendering/RenderReplaced.h" -#include "RuntimeEnabledFeatures.h" #include "core/rendering/GraphicsContextAnnotator.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/LayoutRepainter.h" #include "core/rendering/RenderBlock.h" #include "core/rendering/RenderImage.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderView.h" +#include "platform/LengthFunctions.h" +#include "platform/RuntimeEnabledFeatures.h" #include "platform/graphics/GraphicsContext.h" using namespace std; @@ -81,8 +81,7 @@ void RenderReplaced::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); - LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); + LayoutRepainter repainter(*this, checkForPaintInvalidationDuringLayout()); setHeight(minimumReplacedHeight()); @@ -91,7 +90,7 @@ void RenderReplaced::layout() m_overflow.clear(); addVisualEffectOverflow(); - updateLayerTransform(); + updateLayerTransformAfterLayout(); invalidateBackgroundObscurationStatus(); repainter.repaintAfterLayout(); @@ -103,7 +102,7 @@ void RenderReplaced::intrinsicSizeChanged() int scaledWidth = static_cast<int>(cDefaultWidth * style()->effectiveZoom()); int scaledHeight = static_cast<int>(cDefaultHeight * style()->effectiveZoom()); m_intrinsicSize = IntSize(scaledWidth, scaledHeight); - setNeedsLayoutAndPrefWidthsRecalc(); + setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } void RenderReplaced::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) @@ -196,19 +195,17 @@ bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, const LayoutPoint& paintO // Early exit if the element touches the edges. LayoutUnit top = adjustedPaintOffset.y() + visualOverflowRect().y(); LayoutUnit bottom = adjustedPaintOffset.y() + visualOverflowRect().maxY(); - if (isSelected() && m_inlineBoxWrapper) { - LayoutUnit selTop = paintOffset.y() + m_inlineBoxWrapper->root()->selectionTop(); - LayoutUnit selBottom = paintOffset.y() + selTop + m_inlineBoxWrapper->root()->selectionHeight(); + if (isSelected() && inlineBoxWrapper()) { + LayoutUnit selTop = paintOffset.y() + inlineBoxWrapper()->root().selectionTop(); + LayoutUnit selBottom = paintOffset.y() + selTop + inlineBoxWrapper()->root().selectionHeight(); top = min(selTop, top); bottom = max(selBottom, bottom); } - LayoutRect localRepaintRect = paintInfo.rect; - localRepaintRect.inflate(maximalOutlineSize(paintInfo.phase)); - if (adjustedPaintOffset.x() + visualOverflowRect().x() >= localRepaintRect.maxX() || adjustedPaintOffset.x() + visualOverflowRect().maxX() <= localRepaintRect.x()) + if (adjustedPaintOffset.x() + visualOverflowRect().x() >= paintInfo.rect.maxX() || adjustedPaintOffset.x() + visualOverflowRect().maxX() <= paintInfo.rect.x()) return false; - if (top >= localRepaintRect.maxY() || bottom <= localRepaintRect.y()) + if (top >= paintInfo.rect.maxY() || bottom <= paintInfo.rect.y()) return false; return true; @@ -224,24 +221,15 @@ static inline RenderBlock* firstContainingBlockWithLogicalWidth(const RenderRepl return 0; for (; !containingBlock->isRenderView() && !containingBlock->isBody(); containingBlock = containingBlock->containingBlock()) { - if (containingBlock->style()->logicalWidth().isSpecified()) + if (containingBlock->style()->logicalWidth().isSpecified() + && containingBlock->style()->logicalMinWidth().isSpecified() + && (containingBlock->style()->logicalMaxWidth().isSpecified() || containingBlock->style()->logicalMaxWidth().isUndefined())) return containingBlock; } return 0; } -bool RenderReplaced::hasReplacedLogicalWidth() const -{ - if (style()->logicalWidth().isSpecified()) - return true; - - if (style()->logicalWidth().isAuto()) - return false; - - return firstContainingBlockWithLogicalWidth(this); -} - bool RenderReplaced::hasReplacedLogicalHeight() const { if (style()->logicalHeight().isAuto()) @@ -272,28 +260,21 @@ static inline bool rendererHasAspectRatio(const RenderObject* renderer) return renderer->isImage() || renderer->isCanvas() || renderer->isVideo(); } -void RenderReplaced::computeAspectRatioInformationForRenderBox(RenderBox* contentRenderer, FloatSize& constrainedSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const +void RenderReplaced::computeAspectRatioInformationForRenderBox(RenderBox* contentRenderer, FloatSize& constrainedSize, double& intrinsicRatio) const { FloatSize intrinsicSize; if (contentRenderer) { - contentRenderer->computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); - if (intrinsicRatio) - ASSERT(!isPercentageIntrinsicSize); + contentRenderer->computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio); // Handle zoom & vertical writing modes here, as the embedded document doesn't know about them. - if (!isPercentageIntrinsicSize) { - intrinsicSize.scale(style()->effectiveZoom()); - if (isRenderImage()) - intrinsicSize.scale(toRenderImage(this)->imageDevicePixelRatio()); - } - - if (rendererHasAspectRatio(this) && isPercentageIntrinsicSize) - intrinsicRatio = 1; + intrinsicSize.scale(style()->effectiveZoom()); + if (isRenderImage()) + intrinsicSize.scale(toRenderImage(this)->imageDevicePixelRatio()); // Update our intrinsic size to match what the content renderer has computed, so that when we // constrain the size below, the correct intrinsic size will be obtained for comparison against // min and max widths. - if (intrinsicRatio && !isPercentageIntrinsicSize && !intrinsicSize.isEmpty()) + if (intrinsicRatio && !intrinsicSize.isEmpty()) m_intrinsicSize = LayoutSize(intrinsicSize); if (!isHorizontalWritingMode()) { @@ -302,12 +283,9 @@ void RenderReplaced::computeAspectRatioInformationForRenderBox(RenderBox* conten intrinsicSize = intrinsicSize.transposedSize(); } } else { - computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); - if (intrinsicRatio) { - ASSERT(!isPercentageIntrinsicSize); - if (!intrinsicSize.isEmpty()) - m_intrinsicSize = LayoutSize(isHorizontalWritingMode() ? intrinsicSize : intrinsicSize.transposedSize()); - } + computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio); + if (intrinsicRatio && !intrinsicSize.isEmpty()) + m_intrinsicSize = LayoutSize(isHorizontalWritingMode() ? intrinsicSize : intrinsicSize.transposedSize()); } // Now constrain the intrinsic size along each axis according to minimum and maximum width/heights along the @@ -317,7 +295,7 @@ void RenderReplaced::computeAspectRatioInformationForRenderBox(RenderBox* conten // FIXME: In the long term, it might be better to just return this code more to the way it used to be before this // function was added, since all it has done is make the code more unclear. constrainedSize = intrinsicSize; - if (intrinsicRatio && !isPercentageIntrinsicSize && !intrinsicSize.isEmpty() && style()->logicalWidth().isAuto() && style()->logicalHeight().isAuto()) { + if (intrinsicRatio && !intrinsicSize.isEmpty() && 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! constrainedSize.setWidth(RenderBox::computeReplacedLogicalHeight() * intrinsicSize.width() / intrinsicSize.height()); @@ -358,19 +336,18 @@ LayoutRect RenderReplaced::replacedContentRect(const LayoutSize* overriddenIntri ASSERT_NOT_REACHED(); } - LayoutUnit xOffset = minimumValueForLength(style()->objectPosition().x(), contentRect.width() - finalRect.width(), view()); - LayoutUnit yOffset = minimumValueForLength(style()->objectPosition().y(), contentRect.height() - finalRect.height(), view()); + LayoutUnit xOffset = minimumValueForLength(style()->objectPosition().x(), contentRect.width() - finalRect.width()); + LayoutUnit yOffset = minimumValueForLength(style()->objectPosition().y(), contentRect.height() - finalRect.height()); finalRect.move(xOffset, yOffset); return finalRect; } -void RenderReplaced::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const +void RenderReplaced::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) 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()); + intrinsicSize = FloatSize(intrinsicLogicalWidth().toFloat(), intrinsicLogicalHeight().toFloat()); // Figure out if we need to compute an intrinsic ratio. if (intrinsicSize.isEmpty() || !rendererHasAspectRatio(this)) @@ -387,25 +364,24 @@ LayoutUnit RenderReplaced::computeReplacedLogicalWidth(ShouldComputePreferred sh RenderBox* contentRenderer = embeddedContentBox(); // 10.3.2 Inline, replaced elements: http://www.w3.org/TR/CSS21/visudet.html#inline-replaced-width - bool isPercentageIntrinsicSize = false; double intrinsicRatio = 0; FloatSize constrainedSize; - computeAspectRatioInformationForRenderBox(contentRenderer, constrainedSize, intrinsicRatio, isPercentageIntrinsicSize); + computeAspectRatioInformationForRenderBox(contentRenderer, constrainedSize, intrinsicRatio); if (style()->logicalWidth().isAuto()) { - bool heightIsAuto = style()->logicalHeight().isAuto(); - bool hasIntrinsicWidth = !isPercentageIntrinsicSize && constrainedSize.width() > 0; + bool computedHeightIsAuto = hasAutoHeightOrContainingBlockWithAutoHeight(); + bool hasIntrinsicWidth = constrainedSize.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 (computedHeightIsAuto && hasIntrinsicWidth) return computeReplacedLogicalWidthRespectingMinMaxWidth(constrainedSize.width(), shouldComputePreferred); - bool hasIntrinsicHeight = !isPercentageIntrinsicSize && constrainedSize.height() > 0; - if (intrinsicRatio || isPercentageIntrinsicSize) { + bool hasIntrinsicHeight = constrainedSize.height() > 0; + if (intrinsicRatio) { // 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)) { + if (intrinsicRatio && ((computedHeightIsAuto && !hasIntrinsicWidth && hasIntrinsicHeight) || !computedHeightIsAuto)) { LayoutUnit logicalHeight = computeReplacedLogicalHeight(); return computeReplacedLogicalWidthRespectingMinMaxWidth(roundToInt(round(logicalHeight * intrinsicRatio)), shouldComputePreferred); } @@ -413,21 +389,30 @@ LayoutUnit RenderReplaced::computeReplacedLogicalWidth(ShouldComputePreferred sh // 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 // 'width' is undefined in CSS 2.1. However, it is suggested that, if the containing block's width does not itself depend on the replaced element's width, then // the used value of 'width' is calculated from the constraint equation used for block-level, non-replaced elements in normal flow. - if (heightIsAuto && !hasIntrinsicWidth && !hasIntrinsicHeight) { + if (computedHeightIsAuto && !hasIntrinsicWidth && !hasIntrinsicHeight) { + if (shouldComputePreferred == ComputePreferred) + return 0; // The aforementioned 'constraint equation' used for block-level, non-replaced elements in normal flow: // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block LayoutUnit logicalWidth; - if (RenderBlock* blockWithWidth = firstContainingBlockWithLogicalWidth(this)) + // FIXME: This walking up the containgBlock chain to find the first one with a specified width is bonkers. + // If nothing else, it requires making sure that computeReplacedLogicalWidthRespectingMinMaxWidth cannot + // depend on the width of the replaced element or we infinite loop. Right now we do that in + // firstContainingBlockWithLogicalWidth by checking that width/min-width/max-width are all specified. + // + // Firefox 27 seems to only do this if the <svg> has a viewbox. + if (RenderBlock* blockWithWidth = firstContainingBlockWithLogicalWidth(this)) { logicalWidth = blockWithWidth->computeReplacedLogicalWidthRespectingMinMaxWidth(blockWithWidth->computeReplacedLogicalWidthUsing(blockWithWidth->style()->logicalWidth()), shouldComputePreferred); - else + } else { + // FIXME: If shouldComputePreferred == ComputePreferred, then we're reading this during preferred width + // computation, at which point this is reading stale data from a previous layout. logicalWidth = containingBlock()->availableLogicalWidth(); + } // This solves above equation for 'width' (== logicalWidth). LayoutUnit marginStart = minimumValueForLength(style()->marginStart(), logicalWidth); LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), logicalWidth); logicalWidth = max<LayoutUnit>(0, logicalWidth - (marginStart + marginEnd + (width() - clientWidth()))); - if (isPercentageIntrinsicSize) - logicalWidth = logicalWidth * constrainedSize.width() / 100; return computeReplacedLogicalWidthRespectingMinMaxWidth(logicalWidth, shouldComputePreferred); } } @@ -455,13 +440,12 @@ LayoutUnit RenderReplaced::computeReplacedLogicalHeight() const RenderBox* contentRenderer = embeddedContentBox(); // 10.6.2 Inline, replaced elements: http://www.w3.org/TR/CSS21/visudet.html#inline-replaced-height - bool isPercentageIntrinsicSize = false; double intrinsicRatio = 0; FloatSize constrainedSize; - computeAspectRatioInformationForRenderBox(contentRenderer, constrainedSize, intrinsicRatio, isPercentageIntrinsicSize); + computeAspectRatioInformationForRenderBox(contentRenderer, constrainedSize, intrinsicRatio); bool widthIsAuto = style()->logicalWidth().isAuto(); - bool hasIntrinsicHeight = !isPercentageIntrinsicSize && constrainedSize.height() > 0; + bool hasIntrinsicHeight = constrainedSize.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) @@ -498,7 +482,7 @@ void RenderReplaced::computePreferredLogicalWidths() m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeReplacedLogicalWidth(ComputePreferred); RenderStyle* styleToUse = style(); - if (styleToUse->logicalWidth().isPercent() || styleToUse->logicalMaxWidth().isPercent() || hasRelativeIntrinsicLogicalWidth()) + if (styleToUse->logicalWidth().isPercent() || styleToUse->logicalMaxWidth().isPercent()) m_minPreferredLogicalWidth = 0; if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) { @@ -522,7 +506,7 @@ PositionWithAffinity RenderReplaced::positionForPoint(const LayoutPoint& point) { // FIXME: This code is buggy if the replaced element is relative positioned. InlineBox* box = inlineBoxWrapper(); - RootInlineBox* rootBox = box ? box->root() : 0; + RootInlineBox* rootBox = box ? &box->root() : 0; LayoutUnit top = rootBox ? rootBox->selectionTop() : logicalTop(); LayoutUnit bottom = rootBox ? rootBox->selectionBottom() : logicalBottom(); @@ -545,7 +529,7 @@ PositionWithAffinity RenderReplaced::positionForPoint(const LayoutPoint& point) return RenderBox::positionForPoint(point); } -LayoutRect RenderReplaced::selectionRectForRepaint(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent) +LayoutRect RenderReplaced::selectionRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, bool clipToVisibleContent) { ASSERT(!needsLayout()); @@ -554,9 +538,9 @@ LayoutRect RenderReplaced::selectionRectForRepaint(const RenderLayerModelObject* LayoutRect rect = localSelectionRect(); if (clipToVisibleContent) - computeRectForRepaint(repaintContainer, rect); + mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect); else - rect = localToContainerQuad(FloatRect(rect), repaintContainer).enclosingBoundingBox(); + rect = localToContainerQuad(FloatRect(rect), paintInvalidationContainer).enclosingBoundingBox(); return rect; } @@ -566,15 +550,15 @@ LayoutRect RenderReplaced::localSelectionRect(bool checkWhetherSelected) const if (checkWhetherSelected && !isSelected()) return LayoutRect(); - if (!m_inlineBoxWrapper) + if (!inlineBoxWrapper()) // We're a block-level replaced element. Just return our own dimensions. return LayoutRect(LayoutPoint(), size()); - RootInlineBox* root = m_inlineBoxWrapper->root(); - LayoutUnit newLogicalTop = root->block()->style()->isFlippedBlocksWritingMode() ? m_inlineBoxWrapper->logicalBottom() - root->selectionBottom() : root->selectionTop() - m_inlineBoxWrapper->logicalTop(); - if (root->block()->style()->isHorizontalWritingMode()) - return LayoutRect(0, newLogicalTop, width(), root->selectionHeight()); - return LayoutRect(newLogicalTop, 0, root->selectionHeight(), height()); + RootInlineBox& root = inlineBoxWrapper()->root(); + LayoutUnit newLogicalTop = root.block().style()->isFlippedBlocksWritingMode() ? inlineBoxWrapper()->logicalBottom() - root.selectionBottom() : root.selectionTop() - inlineBoxWrapper()->logicalTop(); + if (root.block().style()->isHorizontalWritingMode()) + return LayoutRect(0, newLogicalTop, width(), root.selectionHeight()); + return LayoutRect(newLogicalTop, 0, root.selectionHeight(), height()); } void RenderReplaced::setSelectionState(SelectionState state) @@ -582,9 +566,16 @@ void RenderReplaced::setSelectionState(SelectionState state) // The selection state for our containing block hierarchy is updated by the base class call. RenderBox::setSelectionState(state); - if (m_inlineBoxWrapper && canUpdateSelectionOnRootLineBoxes()) - if (RootInlineBox* root = m_inlineBoxWrapper->root()) - root->setHasSelectedChildren(isSelected()); + if (!inlineBoxWrapper()) + return; + + // We only include the space below the baseline in our layer's cached repaint rect if the + // image is selected. Since the selection state has changed update the rect. + if (hasLayer()) + layer()->repainter().computeRepaintRects(); + + if (canUpdateSelectionOnRootLineBoxes()) + inlineBoxWrapper()->root().setHasSelectedChildren(isSelected()); } bool RenderReplaced::isSelected() const @@ -600,7 +591,7 @@ bool RenderReplaced::isSelected() const if (s == SelectionStart) return selectionStart == 0; - int end = node()->hasChildNodes() ? node()->childNodeCount() : 1; + int end = node()->hasChildren() ? node()->countChildren() : 1; if (s == SelectionEnd) return selectionEnd == end; if (s == SelectionBoth) @@ -609,28 +600,23 @@ bool RenderReplaced::isSelected() const ASSERT(0); return false; } - -LayoutRect RenderReplaced::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const +LayoutRect RenderReplaced::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const { if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) return LayoutRect(); // The selectionRect can project outside of the overflowRect, so take their union // for repainting to avoid selection painting glitches. - LayoutRect r = unionRect(localSelectionRect(false), visualOverflowRect()); + LayoutRect r = isSelected() ? localSelectionRect() : visualOverflowRect(); RenderView* v = view(); - if (v) { + if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && v) { // FIXME: layoutDelta needs to be applied in parts before/after transforms and // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 r.move(v->layoutDelta()); } - if (style()) { - if (v) - r.inflate(style()->outlineSize()); - } - computeRectForRepaint(repaintContainer, r); + mapRectToPaintInvalidationBacking(paintInvalidationContainer, r); return r; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderReplaced.h b/chromium/third_party/WebKit/Source/core/rendering/RenderReplaced.h index e5db970baa1..fa20c6b9a7e 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderReplaced.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderReplaced.h @@ -33,57 +33,57 @@ public: virtual ~RenderReplaced(); virtual LayoutUnit computeReplacedLogicalWidth(ShouldComputePreferred = ComputeActual) const OVERRIDE; - virtual LayoutUnit computeReplacedLogicalHeight() const; + virtual LayoutUnit computeReplacedLogicalHeight() const OVERRIDE; - bool hasReplacedLogicalWidth() const; bool hasReplacedLogicalHeight() const; + LayoutRect replacedContentRect(const LayoutSize* overriddenIntrinsicSize = 0) const; virtual bool needsPreferredWidthsRecalculation() const OVERRIDE; protected: - virtual void willBeDestroyed(); + virtual void willBeDestroyed() OVERRIDE; - virtual void layout(); + virtual void layout() OVERRIDE; virtual LayoutSize intrinsicSize() const OVERRIDE FINAL { return m_intrinsicSize; } - LayoutRect replacedContentRect(const LayoutSize* overriddenIntrinsicSize = 0) const; - virtual void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const; + virtual void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const OVERRIDE; virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE FINAL; + virtual LayoutUnit intrinsicContentLogicalHeight() const { return intrinsicLogicalHeight(); } + virtual LayoutUnit minimumReplacedHeight() const { return LayoutUnit(); } virtual void setSelectionState(SelectionState) OVERRIDE FINAL; bool isSelected() const; - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; void setIntrinsicSize(const LayoutSize& intrinsicSize) { m_intrinsicSize = intrinsicSize; } virtual void intrinsicSizeChanged(); - virtual bool hasRelativeIntrinsicLogicalWidth() const { return false; } - virtual void paint(PaintInfo&, const LayoutPoint&); + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; bool shouldPaint(PaintInfo&, const LayoutPoint&); 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). + virtual RenderBox* embeddedContentBox() const { return 0; } private: - virtual RenderBox* embeddedContentBox() const { return 0; } - virtual const char* renderName() const { return "RenderReplaced"; } + virtual const char* renderName() const OVERRIDE { return "RenderReplaced"; } - virtual bool canHaveChildren() const { return false; } + virtual bool canHaveChildren() const OVERRIDE { return false; } virtual void computePreferredLogicalWidths() OVERRIDE FINAL; virtual void paintReplaced(PaintInfo&, const LayoutPoint&) { } - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE; + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const OVERRIDE; virtual PositionWithAffinity positionForPoint(const LayoutPoint&) OVERRIDE FINAL; - virtual bool canBeSelectionLeaf() const { return true; } + virtual bool canBeSelectionLeaf() const OVERRIDE { return true; } - virtual LayoutRect selectionRectForRepaint(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent = true) OVERRIDE FINAL; - void computeAspectRatioInformationForRenderBox(RenderBox*, FloatSize& constrainedSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const; + virtual LayoutRect selectionRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, bool clipToVisibleContent = true) OVERRIDE FINAL; + void computeAspectRatioInformationForRenderBox(RenderBox*, FloatSize& constrainedSize, double& intrinsicRatio) const; mutable LayoutSize m_intrinsicSize; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderReplica.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderReplica.cpp index d7885c27909..ad083b27ae9 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderReplica.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderReplica.cpp @@ -30,7 +30,6 @@ #include "core/rendering/RenderReplica.h" #include "core/rendering/GraphicsContextAnnotator.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/RenderLayer.h" namespace WebCore { @@ -58,9 +57,9 @@ RenderReplica::~RenderReplica() void RenderReplica::layout() { - LayoutRectRecorder recorder(*this); setFrameRect(parentBox()->borderBoxRect()); - updateLayerTransform(); + addVisualOverflow(parentBox()->visualOverflowRect()); + updateLayerTransformAfterLayout(); clearNeedsLayout(); } @@ -84,7 +83,7 @@ void RenderReplica::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) // Turn around and paint the parent layer. Use temporary clipRects, so that the layer doesn't end up caching clip rects // computing using the wrong rootLayer RenderLayer* rootPaintingLayer = layer()->transform() ? layer()->parent() : layer()->enclosingTransformedAncestor(); - LayerPaintingInfo paintingInfo(rootPaintingLayer, paintInfo.rect, PaintBehaviorNormal, LayoutSize(), 0, paintInfo.renderRegion); + LayerPaintingInfo paintingInfo(rootPaintingLayer, paintInfo.rect, PaintBehaviorNormal, LayoutSize(), 0); PaintLayerFlags flags = PaintLayerHaveTransparency | PaintLayerAppliedTransform | PaintLayerTemporaryClipRects | PaintLayerPaintingReflection; layer()->parent()->paintLayer(paintInfo.context, paintingInfo, flags); } else if (paintInfo.phase == PaintPhaseMask) diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderReplica.h b/chromium/third_party/WebKit/Source/core/rendering/RenderReplica.h index 43bee56f207..84bbc6fab5f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderReplica.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderReplica.h @@ -39,19 +39,19 @@ public: virtual ~RenderReplica(); - virtual const char* renderName() const { return "RenderReplica"; } + virtual const char* renderName() const OVERRIDE { return "RenderReplica"; } - virtual bool requiresLayer() const { return true; } + virtual LayerType layerTypeRequired() const OVERRIDE { return NormalLayer; } - virtual void layout(); + virtual void layout() OVERRIDE; - virtual void paint(PaintInfo&, const LayoutPoint&); + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; private: RenderReplica(); - virtual bool isReplica() const { return true; } - virtual void computePreferredLogicalWidths(); + virtual bool isReplica() const OVERRIDE { return true; } + virtual void computePreferredLogicalWidths() OVERRIDE; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderRuby.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderRuby.cpp index 8a9ef79b624..5383683eebd 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderRuby.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderRuby.cpp @@ -58,27 +58,27 @@ static inline bool isRubyBeforeBlock(const RenderObject* object) { return isAnonymousRubyInlineBlock(object) && !object->previousSibling() - && object->firstChild() - && object->firstChild()->style()->styleType() == BEFORE; + && toRenderBlock(object)->firstChild() + && toRenderBlock(object)->firstChild()->style()->styleType() == BEFORE; } static inline bool isRubyAfterBlock(const RenderObject* object) { return isAnonymousRubyInlineBlock(object) && !object->nextSibling() - && object->firstChild() - && object->firstChild()->style()->styleType() == AFTER; + && toRenderBlock(object)->firstChild() + && toRenderBlock(object)->firstChild()->style()->styleType() == AFTER; } static inline RenderBlock* rubyBeforeBlock(const RenderObject* ruby) { - RenderObject* child = ruby->firstChild(); + RenderObject* child = ruby->slowFirstChild(); return isRubyBeforeBlock(child) ? toRenderBlock(child) : 0; } static inline RenderBlock* rubyAfterBlock(const RenderObject* ruby) { - RenderObject* child = ruby->lastChild(); + RenderObject* child = ruby->slowLastChild(); return isRubyAfterBlock(child) ? toRenderBlock(child) : 0; } @@ -92,7 +92,7 @@ static RenderBlockFlow* createAnonymousRubyInlineBlock(RenderObject* ruby) static RenderRubyRun* lastRubyRun(const RenderObject* ruby) { - RenderObject* child = ruby->lastChild(); + RenderObject* child = ruby->slowLastChild(); if (child && !child->isRubyRun()) child = child->previousSibling(); ASSERT(!child || child->isRubyRun() || child->isBeforeContent() || child == rubyBeforeBlock(ruby)); @@ -225,7 +225,7 @@ RenderRubyAsBlock::~RenderRubyAsBlock() void RenderRubyAsBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - RenderBlock::styleDidChange(diff, oldStyle); + RenderBlockFlow::styleDidChange(diff, oldStyle); propagateStyleToAnonymousChildren(); } @@ -235,13 +235,13 @@ void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild) if (child->isBeforeContent()) { if (child->isInline()) { // Add generated inline content normally - RenderBlock::addChild(child, firstChild()); + RenderBlockFlow::addChild(child, firstChild()); } else { // Wrap non-inline content with an anonymous inline-block. RenderBlock* beforeBlock = rubyBeforeBlock(this); if (!beforeBlock) { beforeBlock = createAnonymousRubyInlineBlock(this); - RenderBlock::addChild(beforeBlock, firstChild()); + RenderBlockFlow::addChild(beforeBlock, firstChild()); } beforeBlock->addChild(child); } @@ -250,13 +250,13 @@ void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild) if (child->isAfterContent()) { if (child->isInline()) { // Add generated inline content normally - RenderBlock::addChild(child); + RenderBlockFlow::addChild(child); } else { // Wrap non-inline content with an anonymous inline-block. RenderBlock* afterBlock = rubyAfterBlock(this); if (!afterBlock) { afterBlock = createAnonymousRubyInlineBlock(this); - RenderBlock::addChild(afterBlock); + RenderBlockFlow::addChild(afterBlock); } afterBlock->addChild(child); } @@ -265,7 +265,7 @@ void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild) // If the child is a ruby run, just add it normally. if (child->isRubyRun()) { - RenderBlock::addChild(child, beforeChild); + RenderBlockFlow::addChild(child, beforeChild); return; } @@ -289,7 +289,7 @@ void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild) RenderRubyRun* lastRun = lastRubyRun(this); if (!lastRun || lastRun->hasRubyText()) { lastRun = RenderRubyRun::staticCreateRubyRun(this); - RenderBlock::addChild(lastRun, beforeChild); + RenderBlockFlow::addChild(lastRun, beforeChild); } lastRun->addChild(child); } @@ -300,7 +300,7 @@ void RenderRubyAsBlock::removeChild(RenderObject* child) // just use the normal remove method. if (child->parent() == this) { ASSERT(child->isRubyRun() || child->isBeforeContent() || child->isAfterContent() || isAnonymousRubyInlineBlock(child)); - RenderBlock::removeChild(child); + RenderBlockFlow::removeChild(child); return; } // If the child's parent is an anoymous block (must be generated :before/:after content) diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderRuby.h b/chromium/third_party/WebKit/Source/core/rendering/RenderRuby.h index d9da35b9f3b..cd0a7fc6db0 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderRuby.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderRuby.h @@ -56,18 +56,16 @@ public: RenderRubyAsInline(Element*); virtual ~RenderRubyAsInline(); - virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); - virtual void removeChild(RenderObject* child); + virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE; + virtual void removeChild(RenderObject* child) OVERRIDE; protected: - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; private: - virtual bool isRuby() const { return true; } - virtual const char* renderName() const { return "RenderRuby (inline)"; } - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - virtual bool createsAnonymousWrapper() const { return true; } - virtual void removeLeftoverAnonymousBlock(RenderBlock*) { ASSERT_NOT_REACHED(); } + virtual bool isRuby() const OVERRIDE { return true; } + virtual const char* renderName() const OVERRIDE { return "RenderRuby (inline)"; } + virtual bool createsAnonymousWrapper() const OVERRIDE { return true; } }; // <ruby> when used as 'display:block' or 'display:inline-block' @@ -76,18 +74,17 @@ public: RenderRubyAsBlock(Element*); virtual ~RenderRubyAsBlock(); - virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); - virtual void removeChild(RenderObject* child); + virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE; + virtual void removeChild(RenderObject* child) OVERRIDE; protected: - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; private: - virtual bool isRuby() const { return true; } - virtual const char* renderName() const { return "RenderRuby (block)"; } - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - virtual bool createsAnonymousWrapper() const { return true; } - virtual void removeLeftoverAnonymousBlock(RenderBlock*) { ASSERT_NOT_REACHED(); } + virtual bool isRuby() const OVERRIDE { return true; } + virtual const char* renderName() const OVERRIDE { return "RenderRuby (block)"; } + virtual bool createsAnonymousWrapper() const OVERRIDE { return true; } + virtual void removeLeftoverAnonymousBlock(RenderBlock*) OVERRIDE { ASSERT_NOT_REACHED(); } }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderRubyBase.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderRubyBase.cpp index e32478ed14b..1ceeec05486 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderRubyBase.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderRubyBase.cpp @@ -73,8 +73,8 @@ void RenderRubyBase::moveChildren(RenderRubyBase* toBase, RenderObject* beforeCh else moveBlockChildren(toBase, beforeChild); - setNeedsLayoutAndPrefWidthsRecalc(); - toBase->setNeedsLayoutAndPrefWidthsRecalc(); + setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); + toBase->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } void RenderRubyBase::moveInlineChildren(RenderRubyBase* toBase, RenderObject* beforeChild) @@ -130,20 +130,12 @@ void RenderRubyBase::moveBlockChildren(RenderRubyBase* toBase, RenderObject* bef moveChildrenTo(toBase, firstChild(), beforeChild); } -RenderRubyRun* RenderRubyBase::rubyRun() const -{ - ASSERT(parent()); - ASSERT(parent()->isRubyRun()); - - return toRenderRubyRun(parent()); -} - ETextAlign RenderRubyBase::textAlignmentForLine(bool /* endsWithSoftBreak */) const { return JUSTIFY; } -void RenderRubyBase::adjustInlineDirectionLineBounds(int expansionOpportunityCount, float& logicalLeft, float& logicalWidth) const +void RenderRubyBase::adjustInlineDirectionLineBounds(unsigned expansionOpportunityCount, float& logicalLeft, float& logicalWidth) const { int maxPreferredLogicalWidth = this->maxPreferredLogicalWidth(); if (maxPreferredLogicalWidth >= logicalWidth) diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderRubyBase.h b/chromium/third_party/WebKit/Source/core/rendering/RenderRubyBase.h index 197aebba507..98748be1157 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderRubyBase.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderRubyBase.h @@ -43,26 +43,22 @@ public: static RenderRubyBase* createAnonymous(Document*); - virtual const char* renderName() const { return "RenderRubyBase (anonymous)"; } + virtual const char* renderName() const OVERRIDE { return "RenderRubyBase (anonymous)"; } - virtual bool isRubyBase() const { return true; } + virtual bool isRubyBase() const OVERRIDE { return true; } - virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; private: RenderRubyBase(); - virtual ETextAlign textAlignmentForLine(bool endsWithSoftBreak) const; - virtual void adjustInlineDirectionLineBounds(int expansionOpportunityCount, float& logicalLeft, float& logicalWidth) const; - - virtual bool supportsPartialLayout() const OVERRIDE { return false; } + virtual ETextAlign textAlignmentForLine(bool endsWithSoftBreak) const OVERRIDE; + virtual void adjustInlineDirectionLineBounds(unsigned expansionOpportunityCount, float& logicalLeft, float& logicalWidth) const OVERRIDE; void moveChildren(RenderRubyBase* toBase, RenderObject* beforeChild = 0); void moveInlineChildren(RenderRubyBase* toBase, RenderObject* beforeChild = 0); void moveBlockChildren(RenderRubyBase* toBase, RenderObject* beforeChild = 0); - RenderRubyRun* rubyRun() const; - // Allow RenderRubyRun to manipulate the children within ruby bases. friend class RenderRubyRun; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderRubyRun.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderRubyRun.cpp index fe58c872243..09c0146e75a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderRubyRun.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderRubyRun.cpp @@ -32,7 +32,6 @@ #include "core/rendering/RenderRubyRun.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/RenderRubyBase.h" #include "core/rendering/RenderRubyText.h" #include "core/rendering/RenderText.h" @@ -66,11 +65,6 @@ bool RenderRubyRun::hasRubyBase() const return lastChild() && lastChild()->isRubyBase(); } -bool RenderRubyRun::isEmpty() const -{ - return !hasRubyText() && !hasRubyBase(); -} - RenderRubyText* RenderRubyRun::rubyText() const { RenderObject* child = firstChild(); @@ -91,7 +85,7 @@ RenderRubyBase* RenderRubyRun::rubyBaseSafe() RenderRubyBase* base = rubyBase(); if (!base) { base = createRubyBase(); - RenderBlock::addChild(base); + RenderBlockFlow::addChild(base); } return base; } @@ -119,7 +113,7 @@ void RenderRubyRun::addChild(RenderObject* child, RenderObject* beforeChild) // RenderRuby has already ascertained that we can add the child here. ASSERT(!hasRubyText()); // prepend ruby texts as first child - RenderBlock::addChild(child, firstChild()); + RenderBlockFlow::addChild(child, firstChild()); } else if (beforeChild->isRubyText()) { // New text is inserted just before another. // In this case the new text takes the place of the old one, and @@ -133,8 +127,8 @@ void RenderRubyRun::addChild(RenderObject* child, RenderObject* beforeChild) // Note: Doing it in this order and not using RenderRubyRun's methods, // in order to avoid automatic removal of the ruby run in case there is no // other child besides the old ruby text. - RenderBlock::addChild(child, beforeChild); - RenderBlock::removeChild(beforeChild); + RenderBlockFlow::addChild(child, beforeChild); + RenderBlockFlow::removeChild(beforeChild); newRun->addChild(beforeChild); } else if (hasRubyBase()) { // Insertion before a ruby base object. @@ -176,20 +170,19 @@ void RenderRubyRun::removeChild(RenderObject* child) } } - RenderBlock::removeChild(child); + RenderBlockFlow::removeChild(child); if (!beingDestroyed() && !documentBeingDestroyed()) { // Check if our base (if any) is now empty. If so, destroy it. RenderBlock* base = rubyBase(); if (base && !base->firstChild()) { - RenderBlock::removeChild(base); + RenderBlockFlow::removeChild(base); base->deleteLineBoxTree(); base->destroy(); } // If any of the above leaves the run empty, destroy it as well. - if (isEmpty()) { - parent()->removeChild(this); + if (!hasRubyText() && !hasRubyBase()) { deleteLineBoxTree(); destroy(); } @@ -229,8 +222,7 @@ RenderObject* RenderRubyRun::layoutSpecialExcludedChild(bool relayoutChildren, S void RenderRubyRun::layout() { - LayoutRectRecorder recorder(*this); - RenderBlock::layout(); + RenderBlockFlow::layout(); RenderRubyText* rt = rubyText(); if (!rt) diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderRubyRun.h b/chromium/third_party/WebKit/Source/core/rendering/RenderRubyRun.h index 2005bc1322b..118533ae2b2 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderRubyRun.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderRubyRun.h @@ -47,20 +47,19 @@ public: bool hasRubyText() const; bool hasRubyBase() const; - bool isEmpty() const; RenderRubyText* rubyText() const; RenderRubyBase* rubyBase() const; RenderRubyBase* rubyBaseSafe(); // creates the base if it doesn't already exist - virtual RenderObject* layoutSpecialExcludedChild(bool relayoutChildren, SubtreeLayoutScope&); - virtual void layout(); + virtual RenderObject* layoutSpecialExcludedChild(bool relayoutChildren, SubtreeLayoutScope&) OVERRIDE; + virtual void layout() OVERRIDE; - virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; - virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); - virtual void removeChild(RenderObject* child); + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; + virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE; + virtual void removeChild(RenderObject* child) OVERRIDE; - virtual RenderBlock* firstLineBlock() const; - virtual void updateFirstLetter(); + virtual RenderBlock* firstLineBlock() const OVERRIDE; + virtual void updateFirstLetter() OVERRIDE; void getOverhang(bool firstLine, RenderObject* startRenderer, RenderObject* endRenderer, int& startOverhang, int& endOverhang) const; @@ -72,11 +71,10 @@ protected: private: RenderRubyRun(); - virtual bool isRubyRun() const { return true; } - virtual const char* renderName() const { return "RenderRubyRun (anonymous)"; } - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - virtual bool createsAnonymousWrapper() const { return true; } - virtual void removeLeftoverAnonymousBlock(RenderBlock*) { } + virtual bool isRubyRun() const OVERRIDE { return true; } + virtual const char* renderName() const OVERRIDE { return "RenderRubyRun (anonymous)"; } + virtual bool createsAnonymousWrapper() const OVERRIDE { return true; } + virtual void removeLeftoverAnonymousBlock(RenderBlock*) OVERRIDE { } }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderRubyRun, isRubyRun()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderRubyText.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderRubyText.cpp index 3e5a60f0dfb..5e469787347 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderRubyText.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderRubyText.cpp @@ -62,12 +62,12 @@ ETextAlign RenderRubyText::textAlignmentForLine(bool endsWithSoftBreak) const return JUSTIFY; } -void RenderRubyText::adjustInlineDirectionLineBounds(int expansionOpportunityCount, float& logicalLeft, float& logicalWidth) const +void RenderRubyText::adjustInlineDirectionLineBounds(unsigned expansionOpportunityCount, float& logicalLeft, float& logicalWidth) const { ETextAlign textAlign = style()->textAlign(); // FIXME: This check is bogus since user can set the initial value. if (textAlign != RenderStyle::initialTextAlign()) - return RenderBlock::adjustInlineDirectionLineBounds(expansionOpportunityCount, logicalLeft, logicalWidth); + return RenderBlockFlow::adjustInlineDirectionLineBounds(expansionOpportunityCount, logicalLeft, logicalWidth); int maxPreferredLogicalWidth = this->maxPreferredLogicalWidth(); if (maxPreferredLogicalWidth >= logicalWidth) diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderRubyText.h b/chromium/third_party/WebKit/Source/core/rendering/RenderRubyText.h index b1cb992c5eb..1e2b636acdc 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderRubyText.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderRubyText.h @@ -40,19 +40,17 @@ public: RenderRubyText(Element*); virtual ~RenderRubyText(); - virtual const char* renderName() const { return "RenderRubyText"; } + virtual const char* renderName() const OVERRIDE { return "RenderRubyText"; } - virtual bool isRubyText() const { return true; } + virtual bool isRubyText() const OVERRIDE { return true; } - virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; private: - virtual bool avoidsFloats() const; + virtual bool avoidsFloats() const OVERRIDE; - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - - virtual ETextAlign textAlignmentForLine(bool endsWithSoftBreak) const; - virtual void adjustInlineDirectionLineBounds(int expansionOpportunityCount, float& logicalLeft, float& logicalWidth) const; + virtual ETextAlign textAlignmentForLine(bool endsWithSoftBreak) const OVERRIDE; + virtual void adjustInlineDirectionLineBounds(unsigned expansionOpportunityCount, float& logicalLeft, float& logicalWidth) const OVERRIDE; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbar.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbar.cpp index a3aaeacba69..4ea0ba701ef 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbar.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbar.cpp @@ -27,20 +27,21 @@ #include "core/rendering/RenderScrollbar.h" #include "core/css/PseudoStyleRequest.h" -#include "core/frame/Frame.h" #include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/rendering/RenderPart.h" #include "core/rendering/RenderScrollbarPart.h" #include "core/rendering/RenderScrollbarTheme.h" +#include "platform/graphics/GraphicsContext.h" namespace WebCore { -PassRefPtr<Scrollbar> RenderScrollbar::createCustomScrollbar(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, Node* ownerNode, Frame* owningFrame) +PassRefPtr<Scrollbar> RenderScrollbar::createCustomScrollbar(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, Node* ownerNode, LocalFrame* owningFrame) { return adoptRef(new RenderScrollbar(scrollableArea, orientation, ownerNode, owningFrame)); } -RenderScrollbar::RenderScrollbar(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, Node* ownerNode, Frame* owningFrame) +RenderScrollbar::RenderScrollbar(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, Node* ownerNode, LocalFrame* owningFrame) : Scrollbar(scrollableArea, orientation, RegularScrollbar, RenderScrollbarTheme::renderScrollbarTheme()) , m_owner(ownerNode) , m_owningFrame(owningFrame) @@ -148,7 +149,7 @@ void RenderScrollbar::setPressedPart(ScrollbarPart part) PassRefPtr<RenderStyle> RenderScrollbar::getScrollbarPseudoStyle(ScrollbarPart partType, PseudoId pseudoId) { if (!owningRenderer()) - return 0; + return nullptr; RefPtr<RenderStyle> result = owningRenderer()->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId, this, partType), owningRenderer()->style()); // Scrollbars for root frames should always have background color @@ -156,7 +157,7 @@ PassRefPtr<RenderStyle> RenderScrollbar::getScrollbarPseudoStyle(ScrollbarPart p // This is because WebKit assumes scrollbar to be always painted and missing background // causes visual artifact like non-repainted dirty region. if (result && m_owningFrame && m_owningFrame->view() && !m_owningFrame->view()->isTransparent() && !result->hasBackground()) - result->setBackgroundColor(Color::white); + result->setBackgroundColor(StyleColor(Color::white)); return result; } @@ -223,9 +224,9 @@ void RenderScrollbar::updateScrollbarPart(ScrollbarPart partType, bool destroy) if (partType == NoPart) return; - RefPtr<RenderStyle> partStyle = !destroy ? getScrollbarPseudoStyle(partType, pseudoForScrollbarPart(partType)) : PassRefPtr<RenderStyle>(0); + RefPtr<RenderStyle> partStyle = !destroy ? getScrollbarPseudoStyle(partType, pseudoForScrollbarPart(partType)) : PassRefPtr<RenderStyle>(nullptr); - bool needRenderer = !destroy && partStyle && partStyle->display() != NONE && partStyle->visibility() == VISIBLE; + bool needRenderer = !destroy && partStyle && partStyle->display() != NONE; if (needRenderer && partStyle->display() != BLOCK) { // See if we are a button that should not be visible according to OS settings. diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbar.h b/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbar.h index fcb60151a20..7d29c397224 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbar.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbar.h @@ -32,19 +32,19 @@ namespace WebCore { -class Frame; +class LocalFrame; class Node; class RenderBox; class RenderScrollbarPart; class RenderStyle; -class RenderScrollbar : public Scrollbar { +class RenderScrollbar FINAL : public Scrollbar { protected: - RenderScrollbar(ScrollableArea*, ScrollbarOrientation, Node*, Frame*); + RenderScrollbar(ScrollableArea*, ScrollbarOrientation, Node*, LocalFrame*); public: friend class Scrollbar; - static PassRefPtr<Scrollbar> createCustomScrollbar(ScrollableArea*, ScrollbarOrientation, Node*, Frame* owningFrame = 0); + static PassRefPtr<Scrollbar> createCustomScrollbar(ScrollableArea*, ScrollbarOrientation, Node*, LocalFrame* owningFrame = 0); virtual ~RenderScrollbar(); RenderBox* owningRenderer() const; @@ -57,20 +57,20 @@ public: int minimumThumbLength(); - virtual bool isOverlayScrollbar() const { return false; } + virtual bool isOverlayScrollbar() const OVERRIDE { return false; } private: virtual void setParent(Widget*) OVERRIDE; - virtual void setEnabled(bool); + virtual void setEnabled(bool) OVERRIDE; - virtual void paint(GraphicsContext*, const IntRect& damageRect); + virtual void paint(GraphicsContext*, const IntRect& damageRect) OVERRIDE; - virtual void setHoveredPart(ScrollbarPart); - virtual void setPressedPart(ScrollbarPart); + virtual void setHoveredPart(ScrollbarPart) OVERRIDE; + virtual void setPressedPart(ScrollbarPart) OVERRIDE; - virtual void styleChanged(); + virtual void styleChanged() OVERRIDE; - virtual bool isCustomScrollbar() const { return true; } + virtual bool isCustomScrollbar() const OVERRIDE { return true; } void updateScrollbarParts(bool destroy = false); @@ -81,9 +81,9 @@ private: // so we keep a reference to the Node which caused this custom scrollbar creation. // This will not create a reference cycle as the Widget tree is owned by our containing // FrameView which this Node pointer can in no way keep alive. See webkit bug 80610. - RefPtr<Node> m_owner; + RefPtrWillBePersistent<Node> m_owner; - Frame* m_owningFrame; + LocalFrame* m_owningFrame; HashMap<unsigned, RenderScrollbarPart*> m_parts; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbarPart.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbarPart.cpp index 13a35ebb832..927079a1fdf 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbarPart.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbarPart.cpp @@ -26,11 +26,11 @@ #include "config.h" #include "core/rendering/RenderScrollbarPart.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/PaintInfo.h" #include "core/rendering/RenderScrollbar.h" #include "core/rendering/RenderScrollbarTheme.h" #include "core/rendering/RenderView.h" +#include "platform/LengthFunctions.h" using namespace std; @@ -56,7 +56,6 @@ RenderScrollbarPart* RenderScrollbarPart::createAnonymous(Document* document, Re void RenderScrollbarPart::layout() { - LayoutRectRecorder recorder(*this); setLocation(LayoutPoint()); // We don't worry about positioning ourselves. We're just determining our minimum width/height. if (m_scrollbar->orientation() == HorizontalScrollbar) layoutHorizontalPart(); @@ -88,10 +87,10 @@ void RenderScrollbarPart::layoutVerticalPart() } } -static int calcScrollbarThicknessUsing(SizeType sizeType, const Length& length, int containingLength, RenderView* renderView) +static int calcScrollbarThicknessUsing(SizeType sizeType, const Length& length, int containingLength) { if (!length.isIntrinsicOrAuto() || (sizeType == MinSize && length.isAuto())) - return minimumValueForLength(length, containingLength, renderView); + return minimumValueForLength(length, containingLength); return ScrollbarTheme::theme()->scrollbarThickness(); } @@ -99,36 +98,34 @@ void RenderScrollbarPart::computeScrollbarWidth() { if (!m_scrollbar->owningRenderer()) return; - RenderView* renderView = view(); // FIXME: We are querying layout information but nothing guarantees that it's up-to-date, especially since we are called at style change. // FIXME: Querying the style's border information doesn't work on table cells with collapsing borders. int visibleSize = m_scrollbar->owningRenderer()->width() - m_scrollbar->owningRenderer()->style()->borderLeftWidth() - m_scrollbar->owningRenderer()->style()->borderRightWidth(); - int w = calcScrollbarThicknessUsing(MainOrPreferredSize, style()->width(), visibleSize, renderView); - int minWidth = calcScrollbarThicknessUsing(MinSize, style()->minWidth(), visibleSize, renderView); - int maxWidth = style()->maxWidth().isUndefined() ? w : calcScrollbarThicknessUsing(MaxSize, style()->maxWidth(), visibleSize, renderView); + int w = calcScrollbarThicknessUsing(MainOrPreferredSize, style()->width(), visibleSize); + int minWidth = calcScrollbarThicknessUsing(MinSize, style()->minWidth(), visibleSize); + int maxWidth = style()->maxWidth().isUndefined() ? w : calcScrollbarThicknessUsing(MaxSize, style()->maxWidth(), visibleSize); setWidth(max(minWidth, min(maxWidth, w))); // Buttons and track pieces can all have margins along the axis of the scrollbar. - m_marginBox.setLeft(minimumValueForLength(style()->marginLeft(), visibleSize, renderView)); - m_marginBox.setRight(minimumValueForLength(style()->marginRight(), visibleSize, renderView)); + m_marginBox.setLeft(minimumValueForLength(style()->marginLeft(), visibleSize)); + m_marginBox.setRight(minimumValueForLength(style()->marginRight(), visibleSize)); } void RenderScrollbarPart::computeScrollbarHeight() { if (!m_scrollbar->owningRenderer()) return; - RenderView* renderView = view(); // FIXME: We are querying layout information but nothing guarantees that it's up-to-date, especially since we are called at style change. // FIXME: Querying the style's border information doesn't work on table cells with collapsing borders. int visibleSize = m_scrollbar->owningRenderer()->height() - m_scrollbar->owningRenderer()->style()->borderTopWidth() - m_scrollbar->owningRenderer()->style()->borderBottomWidth(); - int h = calcScrollbarThicknessUsing(MainOrPreferredSize, style()->height(), visibleSize, renderView); - int minHeight = calcScrollbarThicknessUsing(MinSize, style()->minHeight(), visibleSize, renderView); - int maxHeight = style()->maxHeight().isUndefined() ? h : calcScrollbarThicknessUsing(MaxSize, style()->maxHeight(), visibleSize, renderView); + int h = calcScrollbarThicknessUsing(MainOrPreferredSize, style()->height(), visibleSize); + int minHeight = calcScrollbarThicknessUsing(MinSize, style()->minHeight(), visibleSize); + int maxHeight = style()->maxHeight().isUndefined() ? h : calcScrollbarThicknessUsing(MaxSize, style()->maxHeight(), visibleSize); setHeight(max(minHeight, min(maxHeight, h))); // Buttons and track pieces can all have margins along the axis of the scrollbar. - m_marginBox.setTop(minimumValueForLength(style()->marginTop(), visibleSize, renderView)); - m_marginBox.setBottom(minimumValueForLength(style()->marginBottom(), visibleSize, renderView)); + m_marginBox.setTop(minimumValueForLength(style()->marginTop(), visibleSize)); + m_marginBox.setBottom(minimumValueForLength(style()->marginBottom(), visibleSize)); } void RenderScrollbarPart::computePreferredLogicalWidths() @@ -141,7 +138,7 @@ void RenderScrollbarPart::computePreferredLogicalWidths() clearPreferredLogicalWidthsDirty(); } -void RenderScrollbarPart::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) +void RenderScrollbarPart::styleWillChange(StyleDifference diff, const RenderStyle& newStyle) { RenderBlock::styleWillChange(diff, newStyle); setInline(false); @@ -154,7 +151,7 @@ void RenderScrollbarPart::styleDidChange(StyleDifference diff, const RenderStyle clearPositionedState(); setFloating(false); setHasOverflowClip(false); - if (oldStyle && m_scrollbar && m_part != NoPart && diff >= StyleDifferenceRepaint) + if (oldStyle && m_scrollbar && m_part != NoPart && (diff.needsRepaint() || diff.needsLayout())) m_scrollbar->theme()->invalidatePart(m_scrollbar, m_part); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbarPart.h b/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbarPart.h index a1f24654f4b..f289ce6f431 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbarPart.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbarPart.h @@ -39,11 +39,11 @@ public: virtual ~RenderScrollbarPart(); - virtual const char* renderName() const { return "RenderScrollbarPart"; } + virtual const char* renderName() const OVERRIDE { return "RenderScrollbarPart"; } - virtual bool requiresLayer() const { return false; } + virtual LayerType layerTypeRequired() const OVERRIDE { return NoLayer; } - virtual void layout(); + virtual void layout() OVERRIDE; void paintIntoRect(GraphicsContext*, const LayoutPoint&, const LayoutRect&); @@ -53,20 +53,31 @@ public: virtual LayoutUnit marginLeft() const OVERRIDE { ASSERT(isIntegerValue(m_marginBox.left())); return m_marginBox.left(); } virtual LayoutUnit marginRight() const OVERRIDE { ASSERT(isIntegerValue(m_marginBox.right())); return m_marginBox.right(); } - virtual bool isRenderScrollbarPart() const { return true; } + virtual bool isRenderScrollbarPart() const OVERRIDE { return true; } RenderObject* rendererOwningScrollbar() const; protected: - virtual void styleWillChange(StyleDifference diff, const RenderStyle* newStyle); - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + virtual void styleWillChange(StyleDifference, const RenderStyle& newStyle) OVERRIDE; + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) OVERRIDE; private: RenderScrollbarPart(RenderScrollbar*, ScrollbarPart); - virtual void computePreferredLogicalWidths(); - - virtual bool supportsPartialLayout() const OVERRIDE { return false; } + virtual void computePreferredLogicalWidths() OVERRIDE; + + // Have all padding getters return 0. The important point here is to avoid resolving percents + // against the containing block, since scroll bar corners don't always have one (so it would + // crash). Scroll bar corners are not actually laid out, and they don't have child content, so + // what we return here doesn't really matter. + virtual LayoutUnit paddingTop() const OVERRIDE { return LayoutUnit(); } + virtual LayoutUnit paddingBottom() const OVERRIDE { return LayoutUnit(); } + virtual LayoutUnit paddingLeft() const OVERRIDE { return LayoutUnit(); } + virtual LayoutUnit paddingRight() const OVERRIDE { return LayoutUnit(); } + virtual LayoutUnit paddingBefore() const OVERRIDE { return LayoutUnit(); } + virtual LayoutUnit paddingAfter() const OVERRIDE { return LayoutUnit(); } + virtual LayoutUnit paddingStart() const OVERRIDE { return LayoutUnit(); } + virtual LayoutUnit paddingEnd() const OVERRIDE { return LayoutUnit(); } void layoutHorizontalPart(); void layoutVerticalPart(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbarTheme.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbarTheme.cpp index 63f1a1e23d5..dad81e83bec 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbarTheme.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbarTheme.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "core/rendering/RenderScrollbar.h" #include "core/rendering/RenderScrollbarTheme.h" +#include "platform/graphics/GraphicsContext.h" #include "platform/scroll/ScrollbarThemeClient.h" #include "wtf/StdLibExtras.h" diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbarTheme.h b/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbarTheme.h index 0b5b56e8145..56431e48b5f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbarTheme.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderScrollbarTheme.h @@ -31,9 +31,8 @@ namespace WebCore { class PlatformMouseEvent; -class Scrollbar; -class RenderScrollbarTheme : public ScrollbarTheme { +class RenderScrollbarTheme FINAL : public ScrollbarTheme { public: virtual ~RenderScrollbarTheme() { } @@ -41,11 +40,10 @@ public: virtual ScrollbarButtonsPlacement buttonsPlacement() const OVERRIDE { return ScrollbarTheme::theme()->buttonsPlacement(); } - virtual bool supportsControlTints() const OVERRIDE { return true; } - virtual void paintScrollCorner(GraphicsContext*, const IntRect& cornerRect) OVERRIDE; virtual bool shouldCenterOnThumb(ScrollbarThemeClient* scrollbar, const PlatformMouseEvent& event) OVERRIDE { return ScrollbarTheme::theme()->shouldCenterOnThumb(scrollbar, event); } + virtual bool shouldSnapBackToDragOrigin(ScrollbarThemeClient* scrollbar, const PlatformMouseEvent& event) OVERRIDE { return ScrollbarTheme::theme()->shouldSnapBackToDragOrigin(scrollbar, event); } virtual double initialAutoscrollTimerDelay() OVERRIDE { return ScrollbarTheme::theme()->initialAutoscrollTimerDelay(); } virtual double autoscrollTimerDelay() OVERRIDE { return ScrollbarTheme::theme()->autoscrollTimerDelay(); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderSelectionInfo.h b/chromium/third_party/WebKit/Source/core/rendering/RenderSelectionInfo.h index d3ec42d5720..6cdb43649f4 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderSelectionInfo.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderSelectionInfo.h @@ -42,18 +42,18 @@ public: RenderSelectionInfoBase(RenderObject* o) : m_object(o) - , m_repaintContainer(o->containerForRepaint()) + , m_repaintContainer(o->containerForPaintInvalidation()) , m_state(o->selectionState()) { } RenderObject* object() const { return m_object; } - RenderLayerModelObject* repaintContainer() const { return m_repaintContainer; } + const RenderLayerModelObject* repaintContainer() const { return m_repaintContainer; } RenderObject::SelectionState state() const { return m_state; } protected: RenderObject* m_object; - RenderLayerModelObject* m_repaintContainer; + const RenderLayerModelObject* m_repaintContainer; RenderObject::SelectionState m_state; }; @@ -62,13 +62,20 @@ class RenderSelectionInfo : public RenderSelectionInfoBase { public: RenderSelectionInfo(RenderObject* o, bool clipToVisibleContent) : RenderSelectionInfoBase(o) - , m_rect(o->canUpdateSelectionOnRootLineBoxes() ? o->selectionRectForRepaint(m_repaintContainer, clipToVisibleContent) : LayoutRect()) { + if (o->canUpdateSelectionOnRootLineBoxes()) { + m_rect = o->selectionRectForPaintInvalidation(m_repaintContainer, clipToVisibleContent); + // FIXME: groupedMapping() leaks the squashing abstraction. See RenderBlockSelectionInfo for more details. + if (m_repaintContainer && m_repaintContainer->groupedMapping()) + RenderLayer::mapRectToRepaintBacking(m_repaintContainer, m_repaintContainer, m_rect); + } else { + m_rect = LayoutRect(); + } } void repaint() { - m_object->repaintUsingContainer(m_repaintContainer, enclosingIntRect(m_rect)); + m_object->invalidatePaintUsingContainer(m_repaintContainer, enclosingIntRect(m_rect), InvalidationSelection); } LayoutRect rect() const { return m_rect; } @@ -83,13 +90,22 @@ class RenderBlockSelectionInfo : public RenderSelectionInfoBase { public: RenderBlockSelectionInfo(RenderBlock* b) : RenderSelectionInfoBase(b) - , m_rects(b->canUpdateSelectionOnRootLineBoxes() ? block()->selectionGapRectsForRepaint(m_repaintContainer) : GapRects()) { + if (b->canUpdateSelectionOnRootLineBoxes()) + m_rects = block()->selectionGapRectsForRepaint(m_repaintContainer); + else + m_rects = GapRects(); } void repaint() { - m_object->repaintUsingContainer(m_repaintContainer, enclosingIntRect(m_rects)); + LayoutRect repaintRect = enclosingIntRect(m_rects); + // FIXME: this is leaking the squashing abstraction. However, removing the groupedMapping() condiitional causes + // RenderBox::mapRectToRepaintBacking to get called, which makes rect adjustments even if you pass the same + // repaintContainer as the render object. Find out why it does that and fix. + if (m_repaintContainer && m_repaintContainer->groupedMapping()) + RenderLayer::mapRectToRepaintBacking(m_repaintContainer, m_repaintContainer, repaintRect); + m_object->invalidatePaintUsingContainer(m_repaintContainer, enclosingIntRect(repaintRect), InvalidationSelection); } RenderBlock* block() const { return toRenderBlock(m_object); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderSlider.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderSlider.cpp index 73e4d67bdda..0dff3af336e 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderSlider.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderSlider.cpp @@ -25,7 +25,6 @@ #include "core/html/HTMLInputElement.h" #include "core/html/shadow/ShadowElementNames.h" #include "core/html/shadow/SliderThumbElement.h" -#include "core/rendering/LayoutRectRecorder.h" #include "wtf/MathExtras.h" using std::min; @@ -63,20 +62,21 @@ void RenderSlider::computePreferredLogicalWidths() { m_minPreferredLogicalWidth = 0; m_maxPreferredLogicalWidth = 0; + RenderStyle* styleToUse = style(); - if (style()->width().isFixed() && style()->width().value() > 0) - m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->width().value()); + if (styleToUse->width().isFixed() && styleToUse->width().value() > 0) + m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->width().value()); else computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth); - if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) { - m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value())); - m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value())); + if (styleToUse->minWidth().isFixed() && styleToUse->minWidth().value() > 0) { + m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->minWidth().value())); + m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->minWidth().value())); } - if (style()->maxWidth().isFixed()) { - m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value())); - m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value())); + if (styleToUse->maxWidth().isFixed()) { + m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->maxWidth().value())); + m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->maxWidth().value())); } LayoutUnit toAdd = borderAndPaddingWidth(); @@ -93,7 +93,6 @@ inline SliderThumbElement* RenderSlider::sliderThumbElement() const void RenderSlider::layout() { - LayoutRectRecorder recorder(*this); // FIXME: Find a way to cascade appearance. // http://webkit.org/b/62535 RenderBox* thumbBox = sliderThumbElement()->renderBox(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderSlider.h b/chromium/third_party/WebKit/Source/core/rendering/RenderSlider.h index a627e2c0489..9d1fc60434b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderSlider.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderSlider.h @@ -26,7 +26,6 @@ namespace WebCore { class HTMLInputElement; -class MouseEvent; class SliderThumbElement; class RenderSlider FINAL : public RenderFlexibleBox { @@ -39,13 +38,13 @@ public: bool inDragMode() const; private: - virtual const char* renderName() const { return "RenderSlider"; } - virtual bool isSlider() const { return true; } + virtual const char* renderName() const OVERRIDE { return "RenderSlider"; } + virtual bool isSlider() const OVERRIDE { return true; } - virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const; + virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const OVERRIDE; virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE; virtual void computePreferredLogicalWidths() OVERRIDE; - virtual void layout(); + virtual void layout() OVERRIDE; SliderThumbElement* sliderThumbElement() const; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTable.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderTable.cpp index 5ca0c17e93e..ea196ecff95 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTable.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTable.cpp @@ -4,7 +4,7 @@ * (C) 1998 Waldo Bastian (bastian@kde.org) * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved. * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) * * This library is free software; you can redistribute it and/or @@ -26,15 +26,15 @@ #include "config.h" #include "core/rendering/RenderTable.h" -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/dom/Document.h" -#include "core/html/HTMLTableElement.h" #include "core/frame/FrameView.h" +#include "core/html/HTMLTableElement.h" #include "core/rendering/AutoTableLayout.h" +#include "core/rendering/FastTextAutosizer.h" #include "core/rendering/FixedTableLayout.h" #include "core/rendering/GraphicsContextAnnotator.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/LayoutRepainter.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderTableCaption.h" @@ -63,6 +63,7 @@ RenderTable::RenderTable(Element* element) , m_needsSectionRecalc(false) , m_columnLogicalWidthChanged(false) , m_columnRenderersValid(false) + , m_hasCellColspanThatDeterminesTableWidth(false) , m_hSpacing(0) , m_vSpacing(0) , m_borderStart(0) @@ -82,20 +83,20 @@ void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldSty RenderBlock::styleDidChange(diff, oldStyle); propagateStyleToAnonymousChildren(); - ETableLayout oldTableLayout = oldStyle ? oldStyle->tableLayout() : TAUTO; + bool oldFixedTableLayout = oldStyle ? oldStyle->isFixedTableLayout() : false; // In the collapsed border model, there is no cell spacing. m_hSpacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing(); m_vSpacing = collapseBorders() ? 0 : style()->verticalBorderSpacing(); m_columnPos[0] = m_hSpacing; - if (!m_tableLayout || style()->tableLayout() != oldTableLayout) { + if (!m_tableLayout || style()->isFixedTableLayout() != oldFixedTableLayout) { if (m_tableLayout) m_tableLayout->willChangeTableLayout(); // According to the CSS2 spec, you only use fixed table layout if an // explicit width is specified on the table. Auto width implies auto table layout. - if (style()->tableLayout() == TFIXED && !style()->logicalWidth().isAuto()) + if (style()->isFixedTableLayout()) m_tableLayout = adoptPtr(new FixedTableLayout(this)); else m_tableLayout = adoptPtr(new AutoTableLayout(this)); @@ -117,6 +118,14 @@ static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, Rend ptr = 0; } +static inline bool needsTableSection(RenderObject* object) +{ + // Return true if 'object' can't exist in an anonymous table without being + // wrapped in a table section box. + EDisplay display = object->style()->display(); + return display != TABLE_CAPTION && display != TABLE_COLUMN_GROUP && display != TABLE_COLUMN; +} + void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) { bool wrapInAnonymousSection = !child->isOutOfFlowPositioned(); @@ -156,9 +165,7 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) default: ASSERT_NOT_REACHED(); } - } else if (child->isTableCell() || child->isTableRow()) - wrapInAnonymousSection = true; - else + } else wrapInAnonymousSection = true; if (child->isTableSection()) @@ -186,16 +193,16 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) } RenderObject* lastBox = beforeChild; - while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && lastBox->style()->display() != TABLE_CAPTION && lastBox->style()->display() != TABLE_COLUMN_GROUP) + while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && needsTableSection(lastBox)) lastBox = lastBox->parent(); if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox)) { if (beforeChild == lastBox) - beforeChild = lastBox->firstChild(); + beforeChild = lastBox->slowFirstChild(); lastBox->addChild(child, beforeChild); return; } - if (beforeChild && !beforeChild->isTableSection() && beforeChild->style()->display() != TABLE_CAPTION && beforeChild->style()->display() != TABLE_COLUMN_GROUP) + if (beforeChild && !beforeChild->isTableSection() && needsTableSection(beforeChild)) beforeChild = 0; RenderTableSection* section = RenderTableSection::createAnonymousWithParentRenderer(this); @@ -253,7 +260,6 @@ void RenderTable::updateLogicalWidth() } RenderBlock* cb = containingBlock(); - RenderView* renderView = view(); LayoutUnit availableLogicalWidth = containingBlockLogicalWidthForContent(); bool hasPerpendicularContainingBlock = cb->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode(); @@ -264,16 +270,14 @@ void RenderTable::updateLogicalWidth() setLogicalWidth(convertStyleLogicalWidthToComputedWidth(styleLogicalWidth, containerWidthInInlineDirection)); else { // Subtract out any fixed margins from our available width for auto width tables. - LayoutUnit marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth, renderView); - LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth, renderView); + LayoutUnit marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth); + LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth); 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) { - // FIXME: Work with regions someday. - availableContentLogicalWidth = shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, toRenderBlockFlow(cb), 0); - } + if (shrinkToAvoidFloats() && cb->containsFloats() && !hasPerpendicularContainingBlock) + availableContentLogicalWidth = shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, toRenderBlockFlow(cb)); // Ensure we aren't bigger than our available width. setLogicalWidth(min<int>(availableContentLogicalWidth, maxPreferredLogicalWidth())); @@ -298,23 +302,10 @@ void RenderTable::updateLogicalWidth() } // Finally, with our true width determined, compute our margins for real. - setMarginStart(0); - setMarginEnd(0); - if (!hasPerpendicularContainingBlock) { - LayoutUnit containerLogicalWidthForAutoMargins = availableLogicalWidth; - if (avoidsFloats() && cb->containsFloats()) - containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(0); // FIXME: Work with regions someday. - ComputedMarginValues marginValues; - bool hasInvertedDirection = cb->style()->isLeftToRightDirection() == style()->isLeftToRightDirection(); - computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, logicalWidth(), - hasInvertedDirection ? marginValues.m_start : marginValues.m_end, - hasInvertedDirection ? marginValues.m_end : marginValues.m_start); - setMarginStart(marginValues.m_start); - setMarginEnd(marginValues.m_end); - } else { - setMarginStart(minimumValueForLength(style()->marginStart(), availableLogicalWidth, renderView)); - setMarginEnd(minimumValueForLength(style()->marginEnd(), availableLogicalWidth, renderView)); - } + ComputedMarginValues marginValues; + computeMarginsForDirection(InlineDirection, cb, availableLogicalWidth, logicalWidth(), marginValues.m_start, marginValues.m_end, style()->marginStart(), style()->marginEnd()); + setMarginStart(marginValues.m_start); + setMarginEnd(marginValues.m_end); // We should NEVER shrink the table below the min-content logical width, or else the table can't accomodate // its own content which doesn't match CSS nor what authors expect. @@ -331,11 +322,11 @@ LayoutUnit RenderTable::convertStyleLogicalWidthToComputedWidth(const Length& st // HTML tables' width styles already include borders and paddings, but CSS tables' width styles do not. LayoutUnit borders = 0; - bool isCSSTable = !node() || !isHTMLTableElement(node()); + bool isCSSTable = !isHTMLTableElement(node()); if (isCSSTable && styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive() && style()->boxSizing() == CONTENT_BOX) borders = borderStart() + borderEnd() + (collapseBorders() ? LayoutUnit() : paddingStart() + paddingEnd()); - return minimumValueForLength(styleLogicalWidth, availableWidth, view()) + borders; + return minimumValueForLength(styleLogicalWidth, availableWidth) + borders; } LayoutUnit RenderTable::convertStyleLogicalHeightToComputedHeight(const Length& styleLogicalHeight) @@ -348,14 +339,12 @@ LayoutUnit RenderTable::convertStyleLogicalHeightToComputedHeight(const Length& // HTML tables size as though CSS height includes border/padding, CSS tables do not. LayoutUnit borders = LayoutUnit(); // FIXME: We cannot apply box-sizing: content-box on <table> which other browsers allow. - if ((node() && isHTMLTableElement(node())) || style()->boxSizing() == BORDER_BOX) { + if (isHTMLTableElement(node()) || style()->boxSizing() == BORDER_BOX) { borders = borderAndPadding; } computedLogicalHeight = styleLogicalHeight.value() - borders; } else if (styleLogicalHeight.isPercent()) computedLogicalHeight = computePercentageLogicalHeight(styleLogicalHeight); - else if (styleLogicalHeight.isViewportPercentage()) - computedLogicalHeight = minimumValueForLength(styleLogicalHeight, 0, view()); else if (styleLogicalHeight.isIntrinsic()) computedLogicalHeight = computeIntrinsicLogicalContentHeightUsing(styleLogicalHeight, logicalHeight() - borderAndPadding, borderAndPadding); else @@ -375,9 +364,14 @@ void RenderTable::layoutCaption(RenderTableCaption* caption) caption->layoutIfNeeded(); } // Apply the margins to the location now that they are definitely available from layout - caption->setLogicalLocation(LayoutPoint(caption->marginStart(), collapsedMarginBeforeForChild(caption) + logicalHeight())); + LayoutUnit captionLogicalTop = collapsedMarginBeforeForChild(caption) + logicalHeight(); + if (view()->layoutState()->isPaginated()) { + captionLogicalTop += caption->paginationStrut(); + caption->setPaginationStrut(0); + } + caption->setLogicalLocation(LayoutPoint(caption->marginStart(), captionLogicalTop)); - if (!selfNeedsLayout() && caption->checkForRepaintDuringLayout()) + if (!selfNeedsLayout() && caption->checkForPaintInvalidationDuringLayout()) caption->repaintDuringLayoutIfMoved(captionRect); setLogicalHeight(logicalHeight() + caption->logicalHeight() + collapsedMarginBeforeForChild(caption) + collapsedMarginAfterForChild(caption)); @@ -409,172 +403,179 @@ void RenderTable::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); - if (simplifiedLayout()) return; + // Note: RenderTable is handled differently than other RenderBlocks and the LayoutScope + // must be created before the table begins laying out. + FastTextAutosizer::LayoutScope fastTextAutosizerLayoutScope(this); + recalcSectionsIfNeeded(); // FIXME: We should do this recalc lazily in borderStart/borderEnd so that we don't have to make sure // to call this before we call borderStart/borderEnd to avoid getting a stale value. recalcBordersInRowDirection(); - LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); - LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode()); - - setLogicalHeight(0); - - LayoutUnit oldLogicalWidth = logicalWidth(); - updateLogicalWidth(); - - SubtreeLayoutScope layouter(this); - - if (logicalWidth() != oldLogicalWidth) { - for (unsigned i = 0; i < m_captions.size(); i++) - layouter.setNeedsLayout(m_captions[i]); - } - // FIXME: The optimisation below doesn't work since the internal table - // layout could have changed. we need to add a flag to the table - // layout that tells us if something has changed in the min max - // calculations to do it correctly. -// if ( oldWidth != width() || columns.size() + 1 != columnPos.size() ) - m_tableLayout->layout(); - - LayoutUnit totalSectionLogicalHeight = 0; - LayoutUnit oldTableLogicalTop = 0; - for (unsigned i = 0; i < m_captions.size(); i++) - oldTableLogicalTop += m_captions[i]->logicalHeight() + m_captions[i]->marginBefore() + m_captions[i]->marginAfter(); + LayoutRepainter repainter(*this, checkForPaintInvalidationDuringLayout()); + SubtreeLayoutScope layouter(*this); - bool collapsing = collapseBorders(); - - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (child->isTableSection()) { - RenderTableSection* section = toRenderTableSection(child); - if (m_columnLogicalWidthChanged) - layouter.setChildNeedsLayout(section); - section->layoutIfNeeded(); - totalSectionLogicalHeight += section->calcRowLogicalHeight(); - if (collapsing) - section->recalcOuterBorder(); - ASSERT(!section->needsLayout()); - } else if (child->isRenderTableCol()) { - child->layoutIfNeeded(); - ASSERT(!child->needsLayout()); - } else { - // FIXME: We should never have other type of children (they should be wrapped in an - // anonymous table section) but our code is too crazy and this can happen in practice. - // Until this is fixed, let's make sure we don't leave non laid out children in the tree. - child->layoutIfNeeded(); - } - } // If any table section moved vertically, we will just repaint everything from that // section down (it is quite unlikely that any of the following sections // did not shift). bool sectionMoved = false; LayoutUnit movedSectionLogicalTop = 0; + { + LayoutState state(*this, locationOffset()); - // FIXME: Collapse caption margin. - if (!m_captions.isEmpty()) { - for (unsigned i = 0; i < m_captions.size(); i++) { - if (m_captions[i]->style()->captionSide() == CAPBOTTOM) - continue; - layoutCaption(m_captions[i]); - } - if (logicalHeight() != oldTableLogicalTop) { - sectionMoved = true; - movedSectionLogicalTop = min(logicalHeight(), oldTableLogicalTop); + setLogicalHeight(0); + + LayoutUnit oldLogicalWidth = logicalWidth(); + updateLogicalWidth(); + + if (logicalWidth() != oldLogicalWidth) { + for (unsigned i = 0; i < m_captions.size(); i++) + layouter.setNeedsLayout(m_captions[i]); } - } + // FIXME: The optimisation below doesn't work since the internal table + // layout could have changed. We need to add a flag to the table + // layout that tells us if something has changed in the min max + // calculations to do it correctly. + // if ( oldWidth != width() || columns.size() + 1 != columnPos.size() ) + m_tableLayout->layout(); + + LayoutUnit totalSectionLogicalHeight = 0; + LayoutUnit oldTableLogicalTop = 0; + for (unsigned i = 0; i < m_captions.size(); i++) + oldTableLogicalTop += m_captions[i]->logicalHeight() + m_captions[i]->marginBefore() + m_captions[i]->marginAfter(); - LayoutUnit borderAndPaddingBefore = borderBefore() + (collapsing ? LayoutUnit() : paddingBefore()); - LayoutUnit borderAndPaddingAfter = borderAfter() + (collapsing ? LayoutUnit() : paddingAfter()); + bool collapsing = collapseBorders(); - setLogicalHeight(logicalHeight() + borderAndPaddingBefore); + for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { + if (child->isTableSection()) { + RenderTableSection* section = toRenderTableSection(child); + if (m_columnLogicalWidthChanged) + layouter.setChildNeedsLayout(section); + section->layoutIfNeeded(); + totalSectionLogicalHeight += section->calcRowLogicalHeight(); + if (collapsing) + section->recalcOuterBorder(); + ASSERT(!section->needsLayout()); + } else if (child->isRenderTableCol()) { + child->layoutIfNeeded(); + ASSERT(!child->needsLayout()); + } else { + // FIXME: We should never have other type of children (they should be wrapped in an + // anonymous table section) but our code is too crazy and this can happen in practice. + // Until this is fixed, let's make sure we don't leave non laid out children in the tree. + child->layoutIfNeeded(); + } + } + + // FIXME: Collapse caption margin. + if (!m_captions.isEmpty()) { + for (unsigned i = 0; i < m_captions.size(); i++) { + if (m_captions[i]->style()->captionSide() == CAPBOTTOM) + continue; + layoutCaption(m_captions[i]); + } + if (logicalHeight() != oldTableLogicalTop) { + sectionMoved = true; + movedSectionLogicalTop = min(logicalHeight(), oldTableLogicalTop); + } + } - if (!isOutOfFlowPositioned()) - updateLogicalHeight(); + LayoutUnit borderAndPaddingBefore = borderBefore() + (collapsing ? LayoutUnit() : paddingBefore()); + LayoutUnit borderAndPaddingAfter = borderAfter() + (collapsing ? LayoutUnit() : paddingAfter()); - LayoutUnit computedLogicalHeight = 0; + setLogicalHeight(logicalHeight() + borderAndPaddingBefore); - Length logicalHeightLength = style()->logicalHeight(); - if (logicalHeightLength.isIntrinsic() || (logicalHeightLength.isSpecified() && logicalHeightLength.isPositive())) - computedLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalHeightLength); + if (!isOutOfFlowPositioned()) + updateLogicalHeight(); - Length logicalMaxHeightLength = style()->logicalMaxHeight(); - if (logicalMaxHeightLength.isIntrinsic() || (logicalMaxHeightLength.isSpecified() && !logicalMaxHeightLength.isNegative())) { - LayoutUnit computedMaxLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalMaxHeightLength); - computedLogicalHeight = min(computedLogicalHeight, computedMaxLogicalHeight); - } + LayoutUnit computedLogicalHeight = 0; - Length logicalMinHeightLength = style()->logicalMinHeight(); - if (logicalMinHeightLength.isIntrinsic() || (logicalMinHeightLength.isSpecified() && !logicalMinHeightLength.isNegative())) { - LayoutUnit computedMinLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalMinHeightLength); - computedLogicalHeight = max(computedLogicalHeight, computedMinLogicalHeight); - } + Length logicalHeightLength = style()->logicalHeight(); + if (logicalHeightLength.isIntrinsic() || (logicalHeightLength.isSpecified() && logicalHeightLength.isPositive())) + computedLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalHeightLength); - distributeExtraLogicalHeight(floorToInt(computedLogicalHeight - totalSectionLogicalHeight)); + Length logicalMaxHeightLength = style()->logicalMaxHeight(); + if (logicalMaxHeightLength.isIntrinsic() || (logicalMaxHeightLength.isSpecified() && !logicalMaxHeightLength.isNegative())) { + LayoutUnit computedMaxLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalMaxHeightLength); + computedLogicalHeight = min(computedLogicalHeight, computedMaxLogicalHeight); + } - for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) - section->layoutRows(); + Length logicalMinHeightLength = style()->logicalMinHeight(); + if (logicalMinHeightLength.isIntrinsic() || (logicalMinHeightLength.isSpecified() && !logicalMinHeightLength.isNegative())) { + LayoutUnit computedMinLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalMinHeightLength); + computedLogicalHeight = max(computedLogicalHeight, computedMinLogicalHeight); + } - if (!topSection() && computedLogicalHeight > totalSectionLogicalHeight && !document().inQuirksMode()) { - // Completely empty tables (with no sections or anything) should at least honor specified height - // in strict mode. - setLogicalHeight(logicalHeight() + computedLogicalHeight); - } + distributeExtraLogicalHeight(floorToInt(computedLogicalHeight - totalSectionLogicalHeight)); - LayoutUnit sectionLogicalLeft = style()->isLeftToRightDirection() ? borderStart() : borderEnd(); - if (!collapsing) - sectionLogicalLeft += style()->isLeftToRightDirection() ? paddingStart() : paddingEnd(); + for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) + section->layoutRows(); - // position the table sections - RenderTableSection* section = topSection(); - while (section) { - if (!sectionMoved && section->logicalTop() != logicalHeight()) { - sectionMoved = true; - movedSectionLogicalTop = min(logicalHeight(), section->logicalTop()) + (style()->isHorizontalWritingMode() ? section->visualOverflowRect().y() : section->visualOverflowRect().x()); + if (!topSection() && computedLogicalHeight > totalSectionLogicalHeight && !document().inQuirksMode()) { + // Completely empty tables (with no sections or anything) should at least honor specified height + // in strict mode. + setLogicalHeight(logicalHeight() + computedLogicalHeight); } - section->setLogicalLocation(LayoutPoint(sectionLogicalLeft, logicalHeight())); - setLogicalHeight(logicalHeight() + section->logicalHeight()); - section = sectionBelow(section); - } + LayoutUnit sectionLogicalLeft = style()->isLeftToRightDirection() ? borderStart() : borderEnd(); + if (!collapsing) + sectionLogicalLeft += style()->isLeftToRightDirection() ? paddingStart() : paddingEnd(); - setLogicalHeight(logicalHeight() + borderAndPaddingAfter); + // position the table sections + RenderTableSection* section = topSection(); + while (section) { + if (!sectionMoved && section->logicalTop() != logicalHeight()) { + sectionMoved = true; + movedSectionLogicalTop = min(logicalHeight(), section->logicalTop()) + (style()->isHorizontalWritingMode() ? section->visualOverflowRect().y() : section->visualOverflowRect().x()); + } + section->setLogicalLocation(LayoutPoint(sectionLogicalLeft, logicalHeight())); - for (unsigned i = 0; i < m_captions.size(); i++) { - if (m_captions[i]->style()->captionSide() != CAPBOTTOM) - continue; - layoutCaption(m_captions[i]); - } + setLogicalHeight(logicalHeight() + section->logicalHeight()); + section = sectionBelow(section); + } + + setLogicalHeight(logicalHeight() + borderAndPaddingAfter); + + for (unsigned i = 0; i < m_captions.size(); i++) { + if (m_captions[i]->style()->captionSide() != CAPBOTTOM) + continue; + layoutCaption(m_captions[i]); + } - if (isOutOfFlowPositioned()) - updateLogicalHeight(); + if (isOutOfFlowPositioned()) + updateLogicalHeight(); - // table can be containing block of positioned elements. - // FIXME: Only pass true if width or height changed. - layoutPositionedObjects(true); + // table can be containing block of positioned elements. + // FIXME: Only pass true if width or height changed. + layoutPositionedObjects(true); - updateLayerTransform(); + updateLayerTransformAfterLayout(); - // Layout was changed, so probably borders too. - invalidateCollapsedBorders(); + // Layout was changed, so probably borders too. + invalidateCollapsedBorders(); - computeOverflow(clientLogicalBottom()); + computeOverflow(clientLogicalBottom()); + } - statePusher.pop(); + // FIXME: This value isn't the intrinsic content logical height, but we need + // to update the value as its used by flexbox layout. crbug.com/367324 + updateIntrinsicContentLogicalHeight(contentLogicalHeight()); if (view()->layoutState()->pageLogicalHeight()) - setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(this, logicalTop())); + setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(*this, logicalTop())); bool didFullRepaint = repainter.repaintAfterLayout(); // Repaint with our new bounds if they are different from our old bounds. - if (!didFullRepaint && sectionMoved) { + if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled() + && !didFullRepaint && sectionMoved) { if (style()->isHorizontalWritingMode()) - repaintRectangle(LayoutRect(visualOverflowRect().x(), movedSectionLogicalTop, visualOverflowRect().width(), visualOverflowRect().maxY() - movedSectionLogicalTop)); + invalidatePaintRectangle(LayoutRect(visualOverflowRect().x(), movedSectionLogicalTop, visualOverflowRect().width(), visualOverflowRect().maxY() - movedSectionLogicalTop)); else - repaintRectangle(LayoutRect(movedSectionLogicalTop, visualOverflowRect().y(), visualOverflowRect().maxX() - movedSectionLogicalTop, visualOverflowRect().height())); + invalidatePaintRectangle(LayoutRect(movedSectionLogicalTop, visualOverflowRect().y(), visualOverflowRect().maxX() - movedSectionLogicalTop, visualOverflowRect().height())); } m_columnLogicalWidthChanged = false; @@ -591,14 +592,10 @@ void RenderTable::recalcCollapsedBorders() for (RenderObject* section = firstChild(); section; section = section->nextSibling()) { if (!section->isTableSection()) continue; - for (RenderObject* row = section->firstChild(); row; row = row->nextSibling()) { - if (!row->isTableRow()) - continue; - for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) { - if (!cell->isTableCell()) - continue; - ASSERT(toRenderTableCell(cell)->table() == this); - toRenderTableCell(cell)->collectBorderValues(m_collapsedBorders); + for (RenderTableRow* row = toRenderTableSection(section)->firstRow(); row; row = row->nextRow()) { + for (RenderTableCell* cell = row->firstCell(); cell; cell = cell->nextCell()) { + ASSERT(cell->table() == this); + cell->collectBorderValues(m_collapsedBorders); } } } @@ -640,10 +637,9 @@ void RenderTable::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) PaintPhase paintPhase = paintInfo.phase; - if (!isRoot()) { + if (!isDocumentElement()) { LayoutRect overflowBox = visualOverflowRect(); flipForWritingMode(overflowBox); - overflowBox.inflate(maximalOutlineSize(paintInfo.phase)); overflowBox.moveBy(adjustedPaintOffset); if (!overflowBox.intersects(paintInfo.rect)) return; @@ -773,13 +769,13 @@ void RenderTable::computePreferredLogicalWidths() m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_captions[i]->minPreferredLogicalWidth()); RenderStyle* styleToUse = style(); - // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for min-width. + // FIXME: This should probably be checking for isSpecified since you should be able to use percentage or calc values for min-width. if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) { m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value())); m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value())); } - // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for maxWidth. + // FIXME: This should probably be checking for isSpecified since you should be able to use percentage or calc values for maxWidth. if (styleToUse->logicalMaxWidth().isFixed()) { // We don't constrain m_minPreferredLogicalWidth as the table should be at least the size of its min-content, regardless of 'max-width'. m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value())); @@ -827,6 +823,10 @@ void RenderTable::appendColumn(unsigned span) unsigned newColumnIndex = m_columns.size(); m_columns.append(ColumnStruct(span)); + // Unless the table has cell(s) with colspan that exceed the number of columns afforded + // by the other rows in the table we can use the fast path when mapping columns to effective columns. + m_hasCellColspanThatDeterminesTableWidth = m_hasCellColspanThatDeterminesTableWidth || span > 1; + // Propagate the change in our columns representation to the sections that don't need // cell recalc. If they do, they will be synced up directly with m_columns later. for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { @@ -901,6 +901,7 @@ void RenderTable::recalcSections() const m_foot = 0; m_firstBody = 0; m_hasColElements = false; + m_hasCellColspanThatDeterminesTableWidth = hasCellColspanThatDeterminesTableWidth(); // We need to get valid pointers to caption, head, foot and first body again RenderObject* nextSibling; @@ -1331,9 +1332,12 @@ void RenderTable::updateFirstLetter() int RenderTable::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const { ASSERT(linePositionMode == PositionOnContainingLine); - LayoutUnit baseline = firstLineBoxBaseline(); - if (baseline != -1) + int baseline = firstLineBoxBaseline(); + if (baseline != -1) { + if (isInline()) + return beforeMarginInLineDirection(direction) + baseline; return baseline; + } return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode); } @@ -1367,9 +1371,9 @@ int RenderTable::firstLineBoxBaseline() const return -1; } -LayoutRect RenderTable::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy) +LayoutRect RenderTable::overflowClipRect(const LayoutPoint& location, OverlayScrollbarSizeRelevancy relevancy) { - LayoutRect rect = RenderBlock::overflowClipRect(location, region, relevancy); + LayoutRect rect = RenderBlock::overflowClipRect(location, relevancy); // If we have a caption, expand the clip to include the caption. // FIXME: Technically this is wrong, but it's virtually impossible to fix this @@ -1395,7 +1399,7 @@ bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu LayoutPoint adjustedLocation = accumulatedOffset + location(); // Check kids first. - if (!hasOverflowClip() || locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region()))) { + if (!hasOverflowClip() || locationInContainer.intersects(overflowClipRect(adjustedLocation))) { for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) { LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), adjustedLocation); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTable.h b/chromium/third_party/WebKit/Source/core/rendering/RenderTable.h index ba7ab67b752..811c28668db 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTable.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTable.h @@ -25,7 +25,7 @@ #ifndef RenderTable_h #define RenderTable_h -#include "CSSPropertyNames.h" +#include "core/CSSPropertyNames.h" #include "core/rendering/RenderBlock.h" #include "core/rendering/style/CollapsedBorderValue.h" #include "wtf/Vector.h" @@ -52,33 +52,33 @@ public: bool collapseBorders() const { return style()->borderCollapse(); } - int borderStart() const { return m_borderStart; } - int borderEnd() const { return m_borderEnd; } - int borderBefore() const; - int borderAfter() const; + virtual int borderStart() const OVERRIDE { return m_borderStart; } + virtual int borderEnd() const OVERRIDE { return m_borderEnd; } + virtual int borderBefore() const OVERRIDE; + virtual int borderAfter() const OVERRIDE; - int borderLeft() const + virtual int borderLeft() const OVERRIDE { if (style()->isHorizontalWritingMode()) return style()->isLeftToRightDirection() ? borderStart() : borderEnd(); return style()->isFlippedBlocksWritingMode() ? borderAfter() : borderBefore(); } - int borderRight() const + virtual int borderRight() const OVERRIDE { if (style()->isHorizontalWritingMode()) return style()->isLeftToRightDirection() ? borderEnd() : borderStart(); return style()->isFlippedBlocksWritingMode() ? borderBefore() : borderAfter(); } - int borderTop() const + virtual int borderTop() const OVERRIDE { if (style()->isHorizontalWritingMode()) return style()->isFlippedBlocksWritingMode() ? borderAfter() : borderBefore(); return style()->isLeftToRightDirection() ? borderStart() : borderEnd(); } - int borderBottom() const + virtual int borderBottom() const OVERRIDE { if (style()->isHorizontalWritingMode()) return style()->isFlippedBlocksWritingMode() ? borderBefore() : borderAfter(); @@ -124,7 +124,7 @@ public: int calcBorderEnd() const; void recalcBordersInRowDirection(); - virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); + virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE; struct ColumnStruct { explicit ColumnStruct(unsigned initialSpan = 1) @@ -171,6 +171,9 @@ public: unsigned colToEffCol(unsigned column) const { + if (!m_hasCellColspanThatDeterminesTableWidth) + return column; + unsigned effColumn = 0; unsigned numColumns = numEffCols(); for (unsigned c = 0; effColumn < numColumns && c + m_columns[effColumn].span - 1 < column; ++effColumn) @@ -180,6 +183,9 @@ public: unsigned effColToCol(unsigned effCol) const { + if (!m_hasCellColspanThatDeterminesTableWidth) + return effCol; + unsigned c = 0; for (unsigned i = 0; i < effCol; i++) c += m_columns[i].span; @@ -221,7 +227,7 @@ public: if (documentBeingDestroyed()) return; m_needsSectionRecalc = true; - setNeedsLayout(); + setNeedsLayoutAndFullPaintInvalidation(); } RenderTableSection* sectionAbove(const RenderTableSection*, SkipEmptySectionsValue = DoNotSkipEmptySections) const; @@ -263,22 +269,21 @@ public: void removeColumn(const RenderTableCol*); protected: - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - virtual void simplifiedNormalFlowLayout(); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; + virtual void simplifiedNormalFlowLayout() OVERRIDE; private: - virtual const char* renderName() const { return "RenderTable"; } + virtual const char* renderName() const OVERRIDE { return "RenderTable"; } - virtual bool isTable() const { return true; } + virtual bool isTable() const OVERRIDE { return true; } - virtual bool avoidsFloats() const { return true; } + virtual bool avoidsFloats() const OVERRIDE { return true; } - virtual void paint(PaintInfo&, const LayoutPoint&); - virtual void paintObject(PaintInfo&, const LayoutPoint&); - virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&); - virtual void paintMask(PaintInfo&, const LayoutPoint&); - virtual void layout(); - virtual bool supportsPartialLayout() const OVERRIDE { return false; } + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; + virtual void paintObject(PaintInfo&, const LayoutPoint&) OVERRIDE; + virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&) OVERRIDE; + virtual void paintMask(PaintInfo&, const LayoutPoint&) OVERRIDE; + virtual void layout() OVERRIDE; virtual void computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) const OVERRIDE; virtual void computePreferredLogicalWidths() OVERRIDE; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; @@ -292,17 +297,17 @@ private: void updateColumnCache() const; void invalidateCachedColumns(); - virtual RenderBlock* firstLineBlock() const; - virtual void updateFirstLetter(); + virtual RenderBlock* firstLineBlock() const OVERRIDE; + virtual void updateFirstLetter() OVERRIDE; virtual void updateLogicalWidth() OVERRIDE; LayoutUnit convertStyleLogicalWidthToComputedWidth(const Length& styleLogicalWidth, LayoutUnit availableWidth); LayoutUnit convertStyleLogicalHeightToComputedHeight(const Length& styleLogicalHeight); - virtual LayoutRect overflowClipRect(const LayoutPoint& location, RenderRegion*, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize); + virtual LayoutRect overflowClipRect(const LayoutPoint& location, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) OVERRIDE; - virtual void addOverflowFromChildren(); + virtual void addOverflowFromChildren() OVERRIDE; void subtractCaptionRect(LayoutRect&) const; @@ -332,6 +337,15 @@ private: bool m_columnLogicalWidthChanged : 1; mutable bool m_columnRenderersValid: 1; + mutable bool m_hasCellColspanThatDeterminesTableWidth : 1; + bool hasCellColspanThatDeterminesTableWidth() const + { + for (unsigned c = 0; c < numEffCols(); c++) { + if (m_columns[c].span > 1) + return true; + } + return false; + } short m_hSpacing; short m_vSpacing; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTableCaption.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderTableCaption.cpp index af677b71de9..24dc5eccb48 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTableCaption.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTableCaption.cpp @@ -48,7 +48,7 @@ void RenderTableCaption::insertedIntoTree() void RenderTableCaption::willBeRemovedFromTree() { - RenderBlock::willBeRemovedFromTree(); + RenderBlockFlow::willBeRemovedFromTree(); table()->removeCaption(this); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTableCaption.h b/chromium/third_party/WebKit/Source/core/rendering/RenderTableCaption.h index 35755a9d03b..d24acf84184 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTableCaption.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTableCaption.h @@ -35,8 +35,6 @@ public: private: virtual bool isTableCaption() const OVERRIDE { return true; } - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - virtual void insertedIntoTree() OVERRIDE; virtual void willBeRemovedFromTree() OVERRIDE; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTableCell.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderTableCell.cpp index 9737da43de8..5cf8270ad12 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTableCell.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTableCell.cpp @@ -25,10 +25,9 @@ #include "config.h" #include "core/rendering/RenderTableCell.h" -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/css/StylePropertySet.h" #include "core/html/HTMLTableCellElement.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/PaintInfo.h" #include "core/rendering/RenderTableCol.h" #include "core/rendering/RenderView.h" @@ -66,7 +65,7 @@ RenderTableCell::RenderTableCell(Element* element) void RenderTableCell::willBeRemovedFromTree() { - RenderBlock::willBeRemovedFromTree(); + RenderBlockFlow::willBeRemovedFromTree(); section()->setNeedsCellRecalc(); section()->removeCachedCollapsedBorders(this); @@ -75,16 +74,16 @@ void RenderTableCell::willBeRemovedFromTree() unsigned RenderTableCell::parseColSpanFromDOM() const { ASSERT(node()); - if (node()->hasTagName(tdTag) || node()->hasTagName(thTag)) - return min<unsigned>(toHTMLTableCellElement(node())->colSpan(), maxColumnIndex); + if (isHTMLTableCellElement(*node())) + return min<unsigned>(toHTMLTableCellElement(*node()).colSpan(), maxColumnIndex); return 1; } unsigned RenderTableCell::parseRowSpanFromDOM() const { ASSERT(node()); - if (node()->hasTagName(tdTag) || node()->hasTagName(thTag)) - return min<unsigned>(toHTMLTableCellElement(node())->rowSpan(), maxRowIndex); + if (isHTMLTableCellElement(*node())) + return min<unsigned>(toHTMLTableCellElement(*node()).rowSpan(), maxRowIndex); return 1; } @@ -99,13 +98,13 @@ void RenderTableCell::updateColAndRowSpanFlags() void RenderTableCell::colSpanOrRowSpanChanged() { ASSERT(node()); - ASSERT(node()->hasTagName(tdTag) || node()->hasTagName(thTag)); + ASSERT(isHTMLTableCellElement(*node())); updateColAndRowSpanFlags(); // FIXME: I suspect that we could return early here if !m_hasColSpan && !m_hasRowSpan. - setNeedsLayoutAndPrefWidthsRecalc(); + setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); if (parent() && section()) section()->setNeedsCellRecalc(); } @@ -149,7 +148,7 @@ void RenderTableCell::computePreferredLogicalWidths() // grids. We must refresh those grids before the child cells try to use them. table()->recalcSectionsIfNeeded(); - RenderBlock::computePreferredLogicalWidths(); + RenderBlockFlow::computePreferredLogicalWidths(); if (node() && style()->autoWrap()) { // See if nowrap was set. Length w = styleOrColLogicalWidth(); @@ -226,8 +225,8 @@ void RenderTableCell::setCellLogicalWidth(int tableLayoutLogicalWidth, SubtreeLa layouter.setNeedsLayout(this); - if (!table()->selfNeedsLayout() && checkForRepaintDuringLayout()) - repaint(); + if (!table()->selfNeedsLayout() && checkForPaintInvalidationDuringLayout()) + paintInvalidationForWholeRenderer(); setLogicalWidth(tableLayoutLogicalWidth); setCellWidthChanged(true); @@ -237,8 +236,6 @@ void RenderTableCell::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); - updateFirstLetter(); int oldCellBaseline = cellBaselinePosition(); @@ -251,11 +248,15 @@ void RenderTableCell::layout() if (isBaselineAligned() && section()->rowBaseline(rowIndex()) && cellBaselinePosition() > section()->rowBaseline(rowIndex())) { int newIntrinsicPaddingBefore = max<LayoutUnit>(0, intrinsicPaddingBefore() - max<LayoutUnit>(0, cellBaselinePosition() - oldCellBaseline)); setIntrinsicPaddingBefore(newIntrinsicPaddingBefore); - SubtreeLayoutScope layouter(this); + SubtreeLayoutScope layouter(*this); layouter.setNeedsLayout(this); layoutBlock(cellWidthChanged()); } + // FIXME: This value isn't the intrinsic content logical height, but we need + // to update the value as its used by flexbox layout. crbug.com/367324 + updateIntrinsicContentLogicalHeight(contentLogicalHeight()); + setCellWidthChanged(false); } @@ -307,25 +308,25 @@ void RenderTableCell::setOverrideLogicalContentHeightFromRowHeight(LayoutUnit ro setOverrideLogicalContentHeight(max<LayoutUnit>(0, rowHeight - borderAndPaddingLogicalHeight())); } -LayoutSize RenderTableCell::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const +LayoutSize RenderTableCell::offsetFromContainer(const RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const { ASSERT(o == container()); - LayoutSize offset = RenderBlock::offsetFromContainer(o, point, offsetDependsOnPoint); + LayoutSize offset = RenderBlockFlow::offsetFromContainer(o, point, offsetDependsOnPoint); if (parent()) offset -= parentBox()->locationOffset(); return offset; } -LayoutRect RenderTableCell::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const +LayoutRect RenderTableCell::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const { // If the table grid is dirty, we cannot get reliable information about adjoining cells, // so we ignore outside borders. This should not be a problem because it means that // the table is going to recalculate the grid, relayout and repaint its current rect, which // includes any outside borders of this cell. if (!table()->collapseBorders() || table()->needsSectionRecalc()) - return RenderBlock::clippedOverflowRectForRepaint(repaintContainer); + return RenderBlockFlow::clippedOverflowRectForPaintInvalidation(paintInvalidationContainer); bool rtl = !styleForCellFlow()->isLeftToRightDirection(); int outlineSize = style()->outlineSize(); @@ -360,24 +361,26 @@ LayoutRect RenderTableCell::clippedOverflowRectForRepaint(const RenderLayerModel LayoutPoint location(max<LayoutUnit>(left, -visualOverflowRect().x()), max<LayoutUnit>(top, -visualOverflowRect().y())); LayoutRect r(-location.x(), -location.y(), location.x() + max(width() + right, visualOverflowRect().maxX()), location.y() + max(height() + bottom, visualOverflowRect().maxY())); - if (RenderView* v = view()) { - // FIXME: layoutDelta needs to be applied in parts before/after transforms and - // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 - r.move(v->layoutDelta()); + if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) { + if (RenderView* v = view()) { + // FIXME: layoutDelta needs to be applied in parts before/after transforms and + // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 + r.move(v->layoutDelta()); + } } - computeRectForRepaint(repaintContainer, r); + mapRectToPaintInvalidationBacking(paintInvalidationContainer, r); return r; } -void RenderTableCell::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& r, bool fixed) const +void RenderTableCell::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& r, bool fixed) const { - if (repaintContainer == this) + if (paintInvalidationContainer == this) return; r.setY(r.y()); RenderView* v = view(); - if ((!v || !v->layoutStateEnabled() || repaintContainer) && parent()) + if ((!v || !v->canMapUsingLayoutStateForContainer(paintInvalidationContainer)) && parent()) r.moveBy(-parentBox()->location()); // Rows are in the same coordinate space, so don't add their offset in. - RenderBlock::computeRectForRepaint(repaintContainer, r, fixed); + RenderBlockFlow::mapRectToPaintInvalidationBacking(paintInvalidationContainer, r, fixed); } LayoutUnit RenderTableCell::cellBaselinePosition() const @@ -396,7 +399,7 @@ void RenderTableCell::styleDidChange(StyleDifference diff, const RenderStyle* ol ASSERT(style()->display() == TABLE_CELL); ASSERT(!row() || row()->rowIndexWasSet()); - RenderBlock::styleDidChange(diff, oldStyle); + RenderBlockFlow::styleDidChange(diff, oldStyle); setHasBoxDecorations(true); if (parent() && section() && oldStyle && style()->height() != oldStyle->height()) @@ -738,7 +741,7 @@ CollapsedBorderValue RenderTableCell::computeCollapsedBeforeBorder(IncludeBorder if (prevCell->section() == section()) prevRow = parent()->previousSibling(); else - prevRow = prevCell->section()->lastChild(); + prevRow = prevCell->section()->lastRow(); if (prevRow) { result = chooseBorder(CollapsedBorderValue(prevRow->style()->borderAfter(), includeColor ? prevRow->resolveColor(afterColorProperty) : Color(), BROW), result); @@ -894,44 +897,44 @@ inline CollapsedBorderValue RenderTableCell::cachedCollapsedBottomBorder(const R int RenderTableCell::borderLeft() const { - return table()->collapseBorders() ? borderHalfLeft(false) : RenderBlock::borderLeft(); + return table()->collapseBorders() ? borderHalfLeft(false) : RenderBlockFlow::borderLeft(); } int RenderTableCell::borderRight() const { - return table()->collapseBorders() ? borderHalfRight(false) : RenderBlock::borderRight(); + return table()->collapseBorders() ? borderHalfRight(false) : RenderBlockFlow::borderRight(); } int RenderTableCell::borderTop() const { - return table()->collapseBorders() ? borderHalfTop(false) : RenderBlock::borderTop(); + return table()->collapseBorders() ? borderHalfTop(false) : RenderBlockFlow::borderTop(); } int RenderTableCell::borderBottom() const { - return table()->collapseBorders() ? borderHalfBottom(false) : RenderBlock::borderBottom(); + return table()->collapseBorders() ? borderHalfBottom(false) : RenderBlockFlow::borderBottom(); } // FIXME: https://bugs.webkit.org/show_bug.cgi?id=46191, make the collapsed border drawing // work with different block flow values instead of being hard-coded to top-to-bottom. int RenderTableCell::borderStart() const { - return table()->collapseBorders() ? borderHalfStart(false) : RenderBlock::borderStart(); + return table()->collapseBorders() ? borderHalfStart(false) : RenderBlockFlow::borderStart(); } int RenderTableCell::borderEnd() const { - return table()->collapseBorders() ? borderHalfEnd(false) : RenderBlock::borderEnd(); + return table()->collapseBorders() ? borderHalfEnd(false) : RenderBlockFlow::borderEnd(); } int RenderTableCell::borderBefore() const { - return table()->collapseBorders() ? borderHalfBefore(false) : RenderBlock::borderBefore(); + return table()->collapseBorders() ? borderHalfBefore(false) : RenderBlockFlow::borderBefore(); } int RenderTableCell::borderAfter() const { - return table()->collapseBorders() ? borderHalfAfter(false) : RenderBlock::borderAfter(); + return table()->collapseBorders() ? borderHalfAfter(false) : RenderBlockFlow::borderAfter(); } int RenderTableCell::borderHalfLeft(bool outer) const @@ -1001,7 +1004,7 @@ int RenderTableCell::borderHalfAfter(bool outer) const void RenderTableCell::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { ASSERT(paintInfo.phase != PaintPhaseCollapsedTableBorders); - RenderBlock::paint(paintInfo, paintOffset); + RenderBlockFlow::paint(paintInfo, paintOffset); } static EBorderStyle collapsedBorderStyle(EBorderStyle style) @@ -1105,14 +1108,11 @@ void RenderTableCell::paintCollapsedBorders(PaintInfo& paintInfo, const LayoutPo if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE) return; - LayoutRect localRepaintRect = paintInfo.rect; - localRepaintRect.inflate(maximalOutlineSize(paintInfo.phase)); - LayoutRect paintRect = LayoutRect(paintOffset + location(), pixelSnappedSize()); - if (paintRect.y() - table()->outerBorderTop() >= localRepaintRect.maxY()) + if (paintRect.y() - table()->outerBorderTop() >= paintInfo.rect.maxY()) return; - if (paintRect.maxY() + table()->outerBorderBottom() <= localRepaintRect.y()) + if (paintRect.maxY() + table()->outerBorderBottom() <= paintInfo.rect.y()) return; GraphicsContext* graphicsContext = paintInfo.context; @@ -1159,7 +1159,7 @@ void RenderTableCell::paintCollapsedBorders(PaintInfo& paintInfo, const LayoutPo for (CollapsedBorder* border = borders.nextBorder(); border; border = borders.nextBorder()) { if (border->borderValue.isSameIgnoringColor(*table()->currentBorderValue())) { drawLineForBoxSide(graphicsContext, border->x1, border->y1, border->x2, border->y2, border->side, - resolveColor(border->borderValue.color()), border->style, 0, 0, antialias); + border->borderValue.color().resolve(style()->visitedDependentColor(CSSPropertyColor)), border->style, 0, 0, antialias); } } } @@ -1186,7 +1186,7 @@ void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, const Lay Color c = backgroundObject->resolveColor(CSSPropertyBackgroundColor); const FillLayer* bgLayer = backgroundObject->style()->backgroundLayers(); - if (bgLayer->hasImage() || c.isValid()) { + if (bgLayer->hasImage() || c.alpha()) { // We have to clip here because the background would paint // on top of the borders otherwise. This only matters for cells and rows. bool shouldClip = backgroundObject->hasLayer() && (backgroundObject == this || backgroundObject == parent()) && tableElt->collapseBorders(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTableCell.h b/chromium/third_party/WebKit/Source/core/rendering/RenderTableCell.h index 9eeb48e4f01..dcffc575763 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTableCell.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTableCell.h @@ -4,7 +4,7 @@ * (C) 1998 Waldo Bastian (bastian@kde.org) * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2013 Apple Inc. 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 @@ -28,6 +28,7 @@ #include "core/rendering/RenderBlockFlow.h" #include "core/rendering/RenderTableRow.h" #include "core/rendering/RenderTableSection.h" +#include "platform/LengthFunctions.h" namespace WebCore { @@ -76,6 +77,9 @@ public: RenderTableSection* section() const { return toRenderTableSection(parent()->parent()); } RenderTable* table() const { return toRenderTable(parent()->parent()->parent()); } + RenderTableCell* previousCell() const; + RenderTableCell* nextCell() const; + unsigned rowIndex() const { // This function shouldn't be called on a detached cell. @@ -97,7 +101,7 @@ public: { // FIXME: This function does too much work, and is very hot during table layout! int adjustedLogicalHeight = pixelSnappedLogicalHeight() - (intrinsicPaddingBefore() + intrinsicPaddingAfter()); - int styleLogicalHeight = valueForLength(style()->logicalHeight(), 0, view()); + int styleLogicalHeight = valueForLength(style()->logicalHeight(), 0); // In strict mode, box-sizing: content-box do the right thing and actually add in the border and padding. // Call computedCSSPadding* directly to avoid including implicitPadding. if (!document().inQuirksMode() && style()->boxSizing() != BORDER_BOX) @@ -108,23 +112,21 @@ public: void setCellLogicalWidth(int constrainedLogicalWidth, SubtreeLayoutScope&); - virtual int borderLeft() const; - virtual int borderRight() const; - virtual int borderTop() const; - virtual int borderBottom() const; - virtual int borderStart() const; - virtual int borderEnd() const; - virtual int borderBefore() const; - virtual int borderAfter() const; + virtual int borderLeft() const OVERRIDE; + virtual int borderRight() const OVERRIDE; + virtual int borderTop() const OVERRIDE; + virtual int borderBottom() const OVERRIDE; + virtual int borderStart() const OVERRIDE; + virtual int borderEnd() const OVERRIDE; + virtual int borderBefore() const OVERRIDE; + virtual int borderAfter() const OVERRIDE; void collectBorderValues(RenderTable::CollapsedBorderValues&) const; static void sortBorderValues(RenderTable::CollapsedBorderValues&); - virtual void layout(); - - virtual bool supportsPartialLayout() const OVERRIDE { return false; } + virtual void layout() OVERRIDE; - virtual void paint(PaintInfo&, const LayoutPoint&); + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; void paintCollapsedBorders(PaintInfo&, const LayoutPoint&); void paintBackgroundsBehindCell(PaintInfo&, const LayoutPoint&, RenderObject* backgroundObject); @@ -155,7 +157,7 @@ public: void setOverrideLogicalContentHeightFromRowHeight(LayoutUnit); - virtual void scrollbarsChanged(bool horizontalScrollbarChanged, bool verticalScrollbarChanged); + virtual void scrollbarsChanged(bool horizontalScrollbarChanged, bool verticalScrollbarChanged) OVERRIDE; bool cellWidthChanged() const { return m_cellWidthChanged; } void setCellWidthChanged(bool b = true) { m_cellWidthChanged = b; } @@ -216,28 +218,28 @@ public: } #endif protected: - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - virtual void computePreferredLogicalWidths(); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; + virtual void computePreferredLogicalWidths() OVERRIDE; virtual void addLayerHitTestRects(LayerHitTestRects&, const RenderLayer* currentCompositedLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const OVERRIDE; private: - virtual const char* renderName() const { return (isAnonymous() || isPseudoElement()) ? "RenderTableCell (anonymous)" : "RenderTableCell"; } + virtual const char* renderName() const OVERRIDE { return (isAnonymous() || isPseudoElement()) ? "RenderTableCell (anonymous)" : "RenderTableCell"; } - virtual bool isTableCell() const { return true; } + virtual bool isTableCell() const OVERRIDE { return true; } virtual void willBeRemovedFromTree() OVERRIDE; virtual void updateLogicalWidth() OVERRIDE; - virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&); - virtual void paintMask(PaintInfo&, const LayoutPoint&); + virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&) OVERRIDE; + virtual void paintMask(PaintInfo&, const LayoutPoint&) OVERRIDE; virtual bool boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance, InlineFlowBox*) const OVERRIDE; - virtual LayoutSize offsetFromContainer(RenderObject*, const LayoutPoint&, bool* offsetDependsOnPoint = 0) const; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE; - virtual void computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect&, bool fixed = false) const OVERRIDE; + virtual LayoutSize offsetFromContainer(const RenderObject*, const LayoutPoint&, bool* offsetDependsOnPoint = 0) const OVERRIDE; + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const OVERRIDE; + virtual void mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect&, bool fixed = false) const OVERRIDE; int borderHalfLeft(bool outer) const; int borderHalfRight(bool outer) const; @@ -278,6 +280,9 @@ private: unsigned parseRowSpanFromDOM() const; unsigned parseColSpanFromDOM() const; + void nextSibling() const WTF_DELETED_FUNCTION; + void previousSibling() const WTF_DELETED_FUNCTION; + // Note MSVC will only pack members if they have identical types, hence we use unsigned instead of bool here. unsigned m_column : 29; unsigned m_cellWidthChanged : 1; @@ -289,6 +294,28 @@ private: DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderTableCell, isTableCell()); +inline RenderTableCell* RenderTableCell::previousCell() const +{ + return toRenderTableCell(RenderObject::previousSibling()); +} + +inline RenderTableCell* RenderTableCell::nextCell() const +{ + return toRenderTableCell(RenderObject::nextSibling()); +} + +inline RenderTableCell* RenderTableRow::firstCell() const +{ + ASSERT(children() == virtualChildren()); + return toRenderTableCell(children()->firstChild()); +} + +inline RenderTableCell* RenderTableRow::lastCell() const +{ + ASSERT(children() == virtualChildren()); + return toRenderTableCell(children()->lastChild()); +} + } // namespace WebCore #endif // RenderTableCell_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTableCol.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderTableCol.cpp index 26c5935f97f..b27a30d75aa 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTableCol.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTableCol.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "core/rendering/RenderTableCol.h" -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/html/HTMLTableColElement.h" #include "core/rendering/RenderTable.h" #include "core/rendering/RenderTableCell.h" @@ -60,13 +60,13 @@ void RenderTableCol::updateFromElement() { unsigned oldSpan = m_span; Node* n = node(); - if (n && (n->hasTagName(colTag) || n->hasTagName(colgroupTag))) { - HTMLTableColElement* tc = toHTMLTableColElement(n); - m_span = tc->span(); + if (isHTMLTableColElement(n)) { + HTMLTableColElement& tc = toHTMLTableColElement(*n); + m_span = tc.span(); } else m_span = !(style() && style()->display() == TABLE_COLUMN_GROUP); if (m_span != oldSpan && style() && parent()) - setNeedsLayoutAndPrefWidthsRecalc(); + setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); } void RenderTableCol::insertedIntoTree() @@ -94,23 +94,23 @@ bool RenderTableCol::canHaveChildren() const return isTableColumnGroup(); } -LayoutRect RenderTableCol::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const +LayoutRect RenderTableCol::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const { // For now, just repaint the whole table. // FIXME: Find a better way to do this, e.g., need to repaint all the cells that we // might have propagated a background color or borders into. - // FIXME: check for repaintContainer each time here? + // FIXME: check for paintInvalidationContainer each time here? RenderTable* parentTable = table(); if (!parentTable) return LayoutRect(); - return parentTable->clippedOverflowRectForRepaint(repaintContainer); + return parentTable->clippedOverflowRectForPaintInvalidation(paintInvalidationContainer); } void RenderTableCol::imageChanged(WrappedImagePtr, const IntRect*) { // FIXME: Repaint only the rect the image paints in. - repaint(); + paintInvalidationForWholeRenderer(); } void RenderTableCol::clearPreferredLogicalWidthsDirtyBits() diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTableCol.h b/chromium/third_party/WebKit/Source/core/rendering/RenderTableCol.h index a28f36085bb..acb7d01e89c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTableCol.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTableCol.h @@ -40,6 +40,10 @@ public: RenderObject* firstChild() const { ASSERT(children() == virtualChildren()); return children()->firstChild(); } RenderObject* lastChild() const { ASSERT(children() == virtualChildren()); return children()->lastChild(); } + // If you have a RenderTableCol, use firstChild or lastChild instead. + void slowFirstChild() const WTF_DELETED_FUNCTION; + void slowLastChild() const WTF_DELETED_FUNCTION; + const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } @@ -77,25 +81,25 @@ public: const BorderValue& borderAdjoiningCellAfter(const RenderTableCell*) const; private: - virtual RenderObjectChildList* virtualChildren() { return children(); } - virtual const RenderObjectChildList* virtualChildren() const { return children(); } + virtual RenderObjectChildList* virtualChildren() OVERRIDE { return children(); } + virtual const RenderObjectChildList* virtualChildren() const OVERRIDE { return children(); } - virtual const char* renderName() const { return "RenderTableCol"; } + virtual const char* renderName() const OVERRIDE { return "RenderTableCol"; } virtual bool isRenderTableCol() const OVERRIDE { return true; } - virtual void updateFromElement(); + virtual void updateFromElement() OVERRIDE; virtual void computePreferredLogicalWidths() OVERRIDE { ASSERT_NOT_REACHED(); } virtual void insertedIntoTree() OVERRIDE; virtual void willBeRemovedFromTree() OVERRIDE; - virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; - virtual bool canHaveChildren() const; - virtual bool requiresLayer() const { return false; } + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; + virtual bool canHaveChildren() const OVERRIDE; + virtual LayerType layerTypeRequired() const OVERRIDE { return NoLayer; } - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE; - virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const OVERRIDE; + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) OVERRIDE; - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; RenderTable* table() const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTableRow.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderTableRow.cpp index 528ae08d38c..f1f7ef78242 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTableRow.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTableRow.cpp @@ -1,10 +1,10 @@ -/** +/* * Copyright (C) 1997 Martin Jones (mjones@kde.org) * (C) 1997 Torben Weis (weis@kde.org) * (C) 1998 Waldo Bastian (bastian@kde.org) * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. 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,12 +25,11 @@ #include "config.h" #include "core/rendering/RenderTableRow.h" -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/dom/Document.h" #include "core/fetch/ImageResource.h" #include "core/rendering/GraphicsContextAnnotator.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/PaintInfo.h" #include "core/rendering/RenderTableCell.h" #include "core/rendering/RenderView.h" @@ -80,7 +79,7 @@ void RenderTableRow::styleDidChange(StyleDifference diff, const RenderStyle* old if (table && !table->selfNeedsLayout() && !table->normalChildNeedsLayout() && oldStyle && oldStyle->border() != style()->border()) table->invalidateCollapsedBorders(); - if (table && oldStyle && diff == StyleDifferenceLayout && needsLayout() && table->collapseBorders() && borderWidthChanged(oldStyle, style())) { + if (table && oldStyle && diff.needsFullLayout() && needsLayout() && table->collapseBorders() && borderWidthChanged(oldStyle, style())) { // If the border width changes on a row, we need to make sure the cells in the row know to lay out again. // This only happens when borders are collapsed, since they end up affecting the border sides of the cell // itself. @@ -112,11 +111,12 @@ void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild) if (!child->isTableCell()) { RenderObject* last = beforeChild; if (!last) - last = lastChild(); + last = lastCell(); if (last && last->isAnonymous() && last->isTableCell() && !last->isBeforeOrAfterContent()) { - if (beforeChild == last) - beforeChild = last->firstChild(); - last->addChild(child, beforeChild); + RenderTableCell* lastCell = toRenderTableCell(last); + if (beforeChild == lastCell) + beforeChild = lastCell->firstChild(); + lastCell->addChild(child, beforeChild); return; } @@ -152,7 +152,7 @@ void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild) ASSERT(!beforeChild || beforeChild->isTableCell()); RenderBox::addChild(cell, beforeChild); - if (beforeChild || nextSibling()) + if (beforeChild || nextRow()) section()->setNeedsCellRecalc(); } @@ -160,74 +160,55 @@ void RenderTableRow::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); - // Table rows do not add translation. - LayoutStateMaintainer statePusher(view(), this, LayoutSize(), style()->isFlippedBlocksWritingMode()); - - bool paginated = view()->layoutState()->isPaginated(); - - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (child->isTableCell()) { - SubtreeLayoutScope layouter(child); - RenderTableCell* cell = toRenderTableCell(child); - if (!cell->needsLayout() && paginated && view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(cell, cell->logicalTop()) != cell->pageLogicalOffset()) - layouter.setChildNeedsLayout(cell); - - if (child->needsLayout()) { - cell->computeAndSetBlockDirectionMargins(table()); - cell->layout(); - } + LayoutState state(*this, LayoutSize()); + + for (RenderTableCell* cell = firstCell(); cell; cell = cell->nextCell()) { + SubtreeLayoutScope layouter(*cell); + if (!cell->needsLayout()) + cell->markForPaginationRelayoutIfNeeded(layouter); + if (cell->needsLayout()) { + cell->computeAndSetBlockDirectionMargins(table()); + cell->layout(); } } - // We only ever need to repaint if our cells didn't, which menas that they didn't need + m_overflow.clear(); + addVisualEffectOverflow(); + + // We only ever need to issue paint invalidations if our cells didn't, which means that they didn't need // layout, so we know that our bounds didn't change. This code is just making up for - // the fact that we did not repaint in setStyle() because we had a layout hint. - // We cannot call repaint() because our clippedOverflowRectForRepaint() is taken from the - // parent table, and being mid-layout, that is invalid. Instead, we repaint our cells. - if (selfNeedsLayout() && checkForRepaintDuringLayout()) { - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (child->isTableCell()) - child->repaint(); + // the fact that we did not invalidate paints in setStyle() because we had a layout hint. + // We cannot call repaint() because our clippedOverflowRectForPaintInvalidation() is taken from the + // parent table, and being mid-layout, that is invalid. Instead, we issue paint invalidations for our cells. + if (selfNeedsLayout() && checkForPaintInvalidation()) { + for (RenderTableCell* cell = firstCell(); cell; cell = cell->nextCell()) { + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) { + // FIXME: Is this needed with Repaint After Layout? + cell->setShouldDoFullPaintInvalidationAfterLayout(true); + } else { + cell->paintInvalidationForWholeRenderer(); + } } } - statePusher.pop(); // RenderTableSection::layoutRows will set our logical height and width later, so it calls updateLayerTransform(). clearNeedsLayout(); } -LayoutRect RenderTableRow::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const -{ - ASSERT(parent()); - - if (repaintContainer == this) - return RenderBox::clippedOverflowRectForRepaint(repaintContainer); - - // For now, just repaint the whole table. - // FIXME: Find a better way to do this, e.g., need to repaint all the cells that we - // might have propagated a background color into. - // FIXME: do repaintContainer checks here - if (RenderTable* parentTable = table()) - return parentTable->clippedOverflowRectForRepaint(repaintContainer); - - return LayoutRect(); -} - // Hit Testing bool RenderTableRow::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) { // Table rows cannot ever be hit tested. Effectively they do not exist. // Just forward to our children always. - for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { + for (RenderTableCell* cell = lastCell(); cell; cell = cell->previousCell()) { // FIXME: We have to skip over inline flows, since they can show up inside table rows // at the moment (a demoted inline <form> for example). If we ever implement a // table-specific hit-test method (which we should do for performance reasons anyway), // then we can remove this check. - if (child->isTableCell() && !toRenderBox(child)->hasSelfPaintingLayer()) { - LayoutPoint cellPoint = flipForWritingModeForChild(toRenderTableCell(child), accumulatedOffset); - if (child->nodeAtPoint(request, result, locationInContainer, cellPoint, action)) { + if (!cell->hasSelfPaintingLayer()) { + LayoutPoint cellPoint = flipForWritingModeForChild(cell, accumulatedOffset); + if (cell->nodeAtPoint(request, result, locationInContainer, cellPoint, action)) { updateHitTestResult(result, locationInContainer.point() - toLayoutSize(cellPoint)); return true; } @@ -251,23 +232,19 @@ void RenderTableRow::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this); paintOutlineForRowIfNeeded(paintInfo, paintOffset); - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (child->isTableCell()) { - // Paint the row background behind the cell. - if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseChildBlockBackground) { - RenderTableCell* cell = toRenderTableCell(child); - cell->paintBackgroundsBehindCell(paintInfo, paintOffset, this); - } - if (!toRenderBox(child)->hasSelfPaintingLayer()) - child->paint(paintInfo, paintOffset); - } + for (RenderTableCell* cell = firstCell(); cell; cell = cell->nextCell()) { + // Paint the row background behind the cell. + if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseChildBlockBackground) + cell->paintBackgroundsBehindCell(paintInfo, paintOffset, this); + if (!cell->hasSelfPaintingLayer()) + cell->paint(paintInfo, paintOffset); } } void RenderTableRow::imageChanged(WrappedImagePtr, const IntRect*) { // FIXME: Examine cells and repaint only the rect the image paints in. - repaint(); + paintInvalidationForWholeRenderer(); } RenderTableRow* RenderTableRow::createAnonymous(Document* document) diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTableRow.h b/chromium/third_party/WebKit/Source/core/rendering/RenderTableRow.h index 735f903c627..8dc3550ed97 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTableRow.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTableRow.h @@ -4,7 +4,7 @@ * (C) 1998 Waldo Bastian (bastian@kde.org) * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2009, 2013 Apple Inc. 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 @@ -36,8 +36,11 @@ class RenderTableRow FINAL : public RenderBox { public: explicit RenderTableRow(Element*); - RenderObject* firstChild() const { ASSERT(children() == virtualChildren()); return children()->firstChild(); } - RenderObject* lastChild() const { ASSERT(children() == virtualChildren()); return children()->lastChild(); } + RenderTableCell* firstCell() const; + RenderTableCell* lastCell() const; + + RenderTableRow* previousRow() const; + RenderTableRow* nextRow() const; const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } @@ -88,28 +91,40 @@ public: const BorderValue& borderAdjoiningStartCell(const RenderTableCell*) const; const BorderValue& borderAdjoiningEndCell(const RenderTableCell*) const; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + private: - virtual RenderObjectChildList* virtualChildren() { return children(); } - virtual const RenderObjectChildList* virtualChildren() const { return children(); } + virtual RenderObjectChildList* virtualChildren() OVERRIDE { return children(); } + virtual const RenderObjectChildList* virtualChildren() const OVERRIDE { return children(); } - virtual const char* renderName() const { return (isAnonymous() || isPseudoElement()) ? "RenderTableRow (anonymous)" : "RenderTableRow"; } + virtual const char* renderName() const OVERRIDE { return (isAnonymous() || isPseudoElement()) ? "RenderTableRow (anonymous)" : "RenderTableRow"; } - virtual bool isTableRow() const { return true; } + virtual bool isTableRow() const OVERRIDE { return true; } virtual void willBeRemovedFromTree() OVERRIDE; - virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); - virtual void layout(); - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const; - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE; + virtual void layout() OVERRIDE; + + virtual LayerType layerTypeRequired() const OVERRIDE + { + if (hasTransform() || hasHiddenBackface() || hasClipPath() || createsGroup() || isStickyPositioned() || style()->shouldCompositeForCurrentAnimations()) + return NormalLayer; + + if (hasOverflowClip()) + return OverflowClipLayer; - virtual bool requiresLayer() const OVERRIDE { return hasOverflowClip() || hasTransform() || hasHiddenBackface() || hasClipPath() || createsGroup(); } + return NoLayer; + } - virtual void paint(PaintInfo&, const LayoutPoint&); + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; - virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) OVERRIDE; - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; + + void nextSibling() const WTF_DELETED_FUNCTION; + void previousSibling() const WTF_DELETED_FUNCTION; RenderObjectChildList m_children; unsigned m_rowIndex : 31; @@ -117,6 +132,28 @@ private: DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderTableRow, isTableRow()); +inline RenderTableRow* RenderTableRow::previousRow() const +{ + return toRenderTableRow(RenderObject::previousSibling()); +} + +inline RenderTableRow* RenderTableRow::nextRow() const +{ + return toRenderTableRow(RenderObject::nextSibling()); +} + +inline RenderTableRow* RenderTableSection::firstRow() const +{ + ASSERT(children() == virtualChildren()); + return toRenderTableRow(children()->firstChild()); +} + +inline RenderTableRow* RenderTableSection::lastRow() const +{ + ASSERT(children() == virtualChildren()); + return toRenderTableRow(children()->lastChild()); +} + } // namespace WebCore #endif // RenderTableRow_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTableSection.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderTableSection.cpp index ab6d4da9c60..d7dfc425eee 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTableSection.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTableSection.cpp @@ -4,7 +4,7 @@ * (C) 1998 Waldo Bastian (bastian@kde.org) * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved. * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) * * This library is free software; you can redistribute it and/or @@ -26,12 +26,9 @@ #include "config.h" #include "core/rendering/RenderTableSection.h" -// FIXME: Remove 'RuntimeEnabledFeatures.h' when http://crbug.com/78724 is closed. -#include "RuntimeEnabledFeatures.h" #include <limits> #include "core/rendering/GraphicsContextAnnotator.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/PaintInfo.h" #include "core/rendering/RenderTableCell.h" #include "core/rendering/RenderTableCol.h" @@ -127,10 +124,10 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild if (!child->isTableRow()) { RenderObject* last = beforeChild; if (!last) - last = lastChild(); + last = lastRow(); if (last && last->isAnonymous() && !last->isBeforeOrAfterContent()) { if (beforeChild == last) - beforeChild = last->firstChild(); + beforeChild = last->slowFirstChild(); last->addChild(child, beforeChild); return; } @@ -289,7 +286,7 @@ void RenderTableSection::populateSpanningRowsHeightFromCell(RenderTableCell* cel spanningRowsHeight.rowHeight[row] = m_rowPos[actualRow + 1] - m_rowPos[actualRow] - borderSpacingForRow(actualRow); if (!spanningRowsHeight.rowHeight[row]) - spanningRowsHeight.rowWithOnlySpanningCells |= rowHasOnlySpanningCells(actualRow); + spanningRowsHeight.isAnyRowWithOnlySpanningCells |= rowHasOnlySpanningCells(actualRow); spanningRowsHeight.totalRowsHeight += spanningRowsHeight.rowHeight[row]; spanningRowsHeight.spanningCellHeightIgnoringBorderSpacing -= borderSpacingForRow(actualRow); @@ -328,6 +325,17 @@ void RenderTableSection::distributeExtraRowSpanHeightToPercentRows(RenderTableCe } } +// Sometimes the multiplication of the 2 values below will overflow an integer. +// So we convert the parameters to 'long long' instead of 'int' to avoid the +// problem in this function. +static void updatePositionIncreasedWithRowHeight(long long extraHeight, long long rowHeight, long long totalHeight, int& accumulatedPositionIncrease, int& remainder) +{ + COMPILE_ASSERT(sizeof(long long int) > sizeof(int), int_should_be_less_than_longlong); + + accumulatedPositionIncrease += (extraHeight * rowHeight) / totalHeight; + remainder += (extraHeight * rowHeight) % totalHeight; +} + void RenderTableSection::distributeExtraRowSpanHeightToAutoRows(RenderTableCell* cell, int totalAutoRowsHeight, int& extraRowSpanningHeight, Vector<int>& rowsHeight) { if (!extraRowSpanningHeight || !totalAutoRowsHeight) @@ -342,8 +350,7 @@ void RenderTableSection::distributeExtraRowSpanHeightToAutoRows(RenderTableCell* // So extra height distributed in auto spanning rows based on their weight in spanning cell. for (unsigned row = rowIndex; row < (rowIndex + rowSpan); row++) { if (m_grid[row].logicalHeight.isAuto()) { - accumulatedPositionIncrease += (extraRowSpanningHeight * rowsHeight[row - rowIndex]) / totalAutoRowsHeight; - remainder += (extraRowSpanningHeight * rowsHeight[row - rowIndex]) % totalAutoRowsHeight; + updatePositionIncreasedWithRowHeight(extraRowSpanningHeight, rowsHeight[row - rowIndex], totalAutoRowsHeight, accumulatedPositionIncrease, remainder); // While whole extra spanning height is distributing in auto spanning rows, rational parts remains // in every integer division. So accumulating all remainder part in integer division and when total remainder @@ -376,8 +383,7 @@ void RenderTableSection::distributeExtraRowSpanHeightToRemainingRows(RenderTable // So extra height distribution in remaining spanning rows based on their weight in spanning cell. for (unsigned row = rowIndex; row < (rowIndex + rowSpan); row++) { if (!m_grid[row].logicalHeight.isPercent()) { - accumulatedPositionIncrease += (extraRowSpanningHeight * rowsHeight[row - rowIndex]) / totalRemainingRowsHeight; - remainder += (extraRowSpanningHeight * rowsHeight[row - rowIndex]) % totalRemainingRowsHeight; + updatePositionIncreasedWithRowHeight(extraRowSpanningHeight, rowsHeight[row - rowIndex], totalRemainingRowsHeight, accumulatedPositionIncrease, remainder); // While whole extra spanning height is distributing in remaining spanning rows, rational parts remains // in every integer division. So accumulating all remainder part in integer division and when total remainder @@ -542,14 +548,31 @@ void RenderTableSection::distributeRowSpanHeightToRows(SpanningRenderTableCells& populateSpanningRowsHeightFromCell(cell, spanningRowsHeight); - if (spanningRowsHeight.rowWithOnlySpanningCells) + // Here we are handling only row(s) who have only rowspanning cells and do not have any empty cell. + if (spanningRowsHeight.isAnyRowWithOnlySpanningCells) updateRowsHeightHavingOnlySpanningCells(cell, spanningRowsHeight); - if (!spanningRowsHeight.totalRowsHeight || spanningRowsHeight.spanningCellHeightIgnoringBorderSpacing <= spanningRowsHeight.totalRowsHeight) { + // This code handle row(s) that have rowspanning cell(s) and at least one empty cell. + // Such rows are not handled below and end up having a height of 0. That would mean + // content overlapping if one of their cells has any content. To avoid the problem, we + // add all the remaining spanning cells' height to the last spanned row. + // This means that we could grow a row past its 'height' or break percentage spreading + // however this is better than overlapping content. + // FIXME: Is there a better algorithm? + if (!spanningRowsHeight.totalRowsHeight) { + if (spanningRowsHeight.spanningCellHeightIgnoringBorderSpacing) + m_rowPos[spanningCellEndIndex] += spanningRowsHeight.spanningCellHeightIgnoringBorderSpacing + borderSpacingForRow(spanningCellEndIndex - 1); + + extraHeightToPropagate = m_rowPos[spanningCellEndIndex] - originalBeforePosition; + continue; + } + + if (spanningRowsHeight.spanningCellHeightIgnoringBorderSpacing <= spanningRowsHeight.totalRowsHeight) { extraHeightToPropagate = m_rowPos[rowIndex + rowSpan] - originalBeforePosition; continue; } + // Below we are handling only row(s) who have at least one visible cell without rowspan value. int totalPercent = 0; int totalAutoRowsHeight = 0; int totalRemainingRowsHeight = spanningRowsHeight.totalRowsHeight; @@ -612,15 +635,15 @@ void RenderTableSection::updateBaselineForCell(RenderTableCell* cell, unsigned r int RenderTableSection::calcRowLogicalHeight() { #ifndef NDEBUG - SetLayoutNeededForbiddenScope layoutForbiddenScope(this); + SetLayoutNeededForbiddenScope layoutForbiddenScope(*this); #endif ASSERT(!needsLayout()); RenderTableCell* cell; - RenderView* viewRenderer = view(); - LayoutStateMaintainer statePusher(viewRenderer); + // FIXME: This shouldn't use the same constructor as RenderView. + LayoutState state(*this); m_rowPos.resize(m_grid.size() + 1); @@ -640,7 +663,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] + minimumValueForLength(m_grid[r].logicalHeight, 0, viewRenderer).round(), 0); + m_rowPos[r + 1] = max(m_rowPos[r] + minimumValueForLength(m_grid[r].logicalHeight, 0).round(), 0); Row& row = m_grid[r].row; unsigned totalCols = row.size(); @@ -653,58 +676,35 @@ int RenderTableSection::calcRowLogicalHeight() if (current.inColSpan && cell->rowSpan() == 1) continue; - if (RuntimeEnabledFeatures::rowSpanLogicalHeightSpreadingEnabled()) { - if (cell->rowSpan() > 1) { - // For row spanning cells, we only handle them for the first row they span. This ensures we take their baseline into account. - if (lastRowSpanCell != cell && cell->rowIndex() == r) { + if (cell->rowSpan() > 1) { + // For row spanning cells, we only handle them for the first row they span. This ensures we take their baseline into account. + if (lastRowSpanCell != cell && cell->rowIndex() == r) { #ifndef NDEBUG - ASSERT(!uniqueCells.contains(cell)); - uniqueCells.add(cell); + ASSERT(!uniqueCells.contains(cell)); + uniqueCells.add(cell); #endif - rowSpanCells.append(cell); - lastRowSpanCell = cell; + rowSpanCells.append(cell); + lastRowSpanCell = cell; - // Find out the baseline. The baseline is set on the first row in a rowSpan. - updateBaselineForCell(cell, r, baselineDescent); - } - continue; + // Find out the baseline. The baseline is set on the first row in a rowSpan. + updateBaselineForCell(cell, r, baselineDescent); } - - ASSERT(cell->rowSpan() == 1); - } else { - // FIXME: We add all the logical row of a rowspan to the last rows - // until crbug.com/78724 is fixed and the runtime flag removed. - // This avoids propagating temporary regressions while we fix the bug. - if ((cell->rowIndex() + cell->rowSpan() - 1) != r) - continue; + continue; } + ASSERT(cell->rowSpan() == 1); + if (cell->hasOverrideHeight()) { - if (!statePusher.didPush()) { - // Technically, we should also push state for the row, but since - // rows don't push a coordinate transform, that's not necessary. - statePusher.push(this, locationOffset()); - } cell->clearIntrinsicPadding(); cell->clearOverrideSize(); cell->forceChildLayout(); } - if (RuntimeEnabledFeatures::rowSpanLogicalHeightSpreadingEnabled()) { - m_rowPos[r + 1] = max(m_rowPos[r + 1], m_rowPos[r] + cell->logicalHeightForRowSizing()); - - // Find out the baseline. - updateBaselineForCell(cell, r, baselineDescent); - } else { - // For row spanning cells, |r| is the last row in the span. - unsigned cellStartRow = cell->rowIndex(); + m_rowPos[r + 1] = max(m_rowPos[r + 1], m_rowPos[r] + cell->logicalHeightForRowSizing()); - m_rowPos[r + 1] = max(m_rowPos[r + 1], m_rowPos[cellStartRow] + cell->logicalHeightForRowSizing()); - - // Find out the baseline. - updateBaselineForCell(cell, cellStartRow, baselineDescent); - } + // Find out the baseline. + updateBaselineForCell(cell, r, baselineDescent); } } @@ -713,15 +713,11 @@ int RenderTableSection::calcRowLogicalHeight() m_rowPos[r + 1] = max(m_rowPos[r + 1], m_rowPos[r]); } - if (!rowSpanCells.isEmpty()) { - ASSERT(RuntimeEnabledFeatures::rowSpanLogicalHeightSpreadingEnabled()); + if (!rowSpanCells.isEmpty()) distributeRowSpanHeightToRows(rowSpanCells); - } ASSERT(!needsLayout()); - statePusher.pop(); - return m_rowPos[m_grid.size()]; } @@ -731,17 +727,15 @@ void RenderTableSection::layout() ASSERT(!needsCellRecalc()); ASSERT(!table()->needsSectionRecalc()); - LayoutRectRecorder recorder(*this); - // addChild may over-grow m_grid but we don't want to throw away the memory too early as addChild // can be called in a loop (e.g during parsing). Doing it now ensures we have a stable-enough structure. m_grid.shrinkToFit(); - LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode()); + LayoutState state(*this, locationOffset()); const Vector<int>& columnPos = table()->columnPositions(); - SubtreeLayoutScope layouter(this); + SubtreeLayoutScope layouter(*this); for (unsigned r = 0; r < m_grid.size(); ++r) { Row& row = m_grid[r].row; unsigned cols = row.size(); @@ -764,11 +758,13 @@ void RenderTableSection::layout() cell->setCellLogicalWidth(tableLayoutLogicalWidth, layouter); } - if (RenderTableRow* rowRenderer = m_grid[r].rowRenderer) + if (RenderTableRow* rowRenderer = m_grid[r].rowRenderer) { + if (!rowRenderer->needsLayout()) + rowRenderer->markForPaginationRelayoutIfNeeded(layouter); rowRenderer->layoutIfNeeded(); + } } - statePusher.pop(); clearNeedsLayout(); } @@ -874,11 +870,13 @@ static bool shouldFlexCellChild(RenderObject* cellDescendant) void RenderTableSection::layoutRows() { #ifndef NDEBUG - SetLayoutNeededForbiddenScope layoutForbiddenScope(this); + SetLayoutNeededForbiddenScope layoutForbiddenScope(*this); #endif ASSERT(!needsLayout()); + // FIXME: Changing the height without a layout can change the overflow so it seems wrong. + unsigned totalRows = m_grid.size(); // Set the width of our section now. The rows will also be this width. @@ -890,7 +888,7 @@ void RenderTableSection::layoutRows() int vspacing = table()->vBorderSpacing(); unsigned nEffCols = table()->numEffCols(); - LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode()); + LayoutState state(*this, locationOffset()); for (unsigned r = 0; r < totalRows; r++) { // Set the row's x/y position and width/height. @@ -898,7 +896,9 @@ void RenderTableSection::layoutRows() rowRenderer->setLocation(LayoutPoint(0, m_rowPos[r])); rowRenderer->setLogicalWidth(logicalWidth()); rowRenderer->setLogicalHeight(m_rowPos[r + 1] - m_rowPos[r] - vspacing); - rowRenderer->updateLayerTransform(); + rowRenderer->updateLayerTransformAfterLayout(); + rowRenderer->clearAllOverflows(); + rowRenderer->addVisualEffectOverflow(); } int rowHeightIncreaseForPagination = 0; @@ -966,15 +966,15 @@ void RenderTableSection::layoutRows() } } - SubtreeLayoutScope layouter(cell); + SubtreeLayoutScope layouter(*cell); cell->computeIntrinsicPadding(rHeight, layouter); LayoutRect oldCellRect = cell->frameRect(); setLogicalPositionForCell(cell, c); - if (!cell->needsLayout() && view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(cell, cell->logicalTop()) != cell->pageLogicalOffset()) - layouter.setChildNeedsLayout(cell); + if (!cell->needsLayout()) + cell->markForPaginationRelayoutIfNeeded(layouter); cell->layoutIfNeeded(); @@ -983,20 +983,27 @@ void RenderTableSection::layoutRows() // 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) - rowHeightIncreaseForPagination = max<int>(rowHeightIncreaseForPagination, cell->logicalHeight() - rHeight); + LayoutUnit oldLogicalHeight = cell->logicalHeight(); + if (oldLogicalHeight > rHeight) + rowHeightIncreaseForPagination = max<int>(rowHeightIncreaseForPagination, oldLogicalHeight - rHeight); cell->setLogicalHeight(rHeight); + cell->computeOverflow(oldLogicalHeight, false); } LayoutSize childOffset(cell->location() - oldCellRect.location()); if (childOffset.width() || childOffset.height()) { - view()->addLayoutDelta(childOffset); + if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + view()->addLayoutDelta(childOffset); // If the child moved, we have to repaint it as well as any floating/positioned - // descendants. An exception is if we need a layout. In this case, we know we're going to + // descendants. An exception is if we need a layout. In this case, we know we're going to // repaint ourselves (and the child) anyway. - if (!table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout()) - cell->repaintDuringLayoutIfMoved(oldCellRect); + if (!table()->selfNeedsLayout() && cell->checkForPaintInvalidation()) { + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + cell->setMayNeedPaintInvalidation(true); + else + cell->repaintDuringLayoutIfMoved(oldCellRect); + } } } if (rowHeightIncreaseForPagination) { @@ -1004,8 +1011,11 @@ void RenderTableSection::layoutRows() m_rowPos[rowIndex] += rowHeightIncreaseForPagination; for (unsigned c = 0; c < nEffCols; ++c) { Vector<RenderTableCell*, 1>& cells = cellAt(r, c).cells; - for (size_t i = 0; i < cells.size(); ++i) - cells[i]->setLogicalHeight(cells[i]->logicalHeight() + rowHeightIncreaseForPagination); + for (size_t i = 0; i < cells.size(); ++i) { + LayoutUnit oldLogicalHeight = cells[i]->logicalHeight(); + cells[i]->setLogicalHeight(oldLogicalHeight + rowHeightIncreaseForPagination); + cells[i]->computeOverflow(oldLogicalHeight, false); + } } } } @@ -1015,8 +1025,6 @@ void RenderTableSection::layoutRows() setLogicalHeight(m_rowPos[totalRows]); computeOverflowFromCells(totalRows, nEffCols); - - statePusher.pop(); } void RenderTableSection::computeOverflowFromCells() @@ -1062,7 +1070,7 @@ void RenderTableSection::computeOverflowFromCells(unsigned totalRows, unsigned n ASSERT(hasOverflowingCell == this->hasOverflowingCell()); } -int RenderTableSection::calcOuterBorderBefore() const +int RenderTableSection::calcBlockDirectionOuterBorder(BlockBorderSide side) const { unsigned totalCols = table()->numEffCols(); if (!m_grid.size() || !totalCols) @@ -1070,13 +1078,13 @@ int RenderTableSection::calcOuterBorderBefore() const unsigned borderWidth = 0; - const BorderValue& sb = style()->borderBefore(); + const BorderValue& sb = side == BorderBefore ? style()->borderBefore() : style()->borderAfter(); if (sb.style() == BHIDDEN) return -1; if (sb.style() > BHIDDEN) borderWidth = sb.width(); - const BorderValue& rb = firstChild()->style()->borderBefore(); + const BorderValue& rb = side == BorderBefore ? firstRow()->style()->borderBefore() : lastRow()->style()->borderAfter(); if (rb.style() == BHIDDEN) return -1; if (rb.style() > BHIDDEN && rb.width() > borderWidth) @@ -1084,14 +1092,15 @@ int RenderTableSection::calcOuterBorderBefore() const bool allHidden = true; for (unsigned c = 0; c < totalCols; c++) { - const CellStruct& current = cellAt(0, c); + const CellStruct& current = cellAt(side == BorderBefore ? 0 : m_grid.size() - 1, c); if (current.inColSpan || !current.hasCells()) continue; - const BorderValue& cb = current.primaryCell()->style()->borderBefore(); // FIXME: Make this work with perpendicular and flipped cells. + const RenderStyle* primaryCellStyle = current.primaryCell()->style(); + const BorderValue& cb = side == BorderBefore ? primaryCellStyle->borderBefore() : primaryCellStyle->borderAfter(); // FIXME: Make this work with perpendicular and flipped cells. // FIXME: Don't repeat for the same col group RenderTableCol* colGroup = table()->colElement(c); if (colGroup) { - const BorderValue& gb = colGroup->style()->borderBefore(); + const BorderValue& gb = side == BorderBefore ? colGroup->style()->borderBefore() : colGroup->style()->borderAfter(); if (gb.style() == BHIDDEN || cb.style() == BHIDDEN) continue; allHidden = false; @@ -1110,76 +1119,28 @@ int RenderTableSection::calcOuterBorderBefore() const if (allHidden) return -1; + if (side == BorderAfter) + borderWidth++; // Distribute rounding error return borderWidth / 2; } -int RenderTableSection::calcOuterBorderAfter() const +int RenderTableSection::calcInlineDirectionOuterBorder(InlineBorderSide side) const { unsigned totalCols = table()->numEffCols(); if (!m_grid.size() || !totalCols) return 0; + unsigned colIndex = side == BorderStart ? 0 : totalCols - 1; unsigned borderWidth = 0; - const BorderValue& sb = style()->borderAfter(); + const BorderValue& sb = side == BorderStart ? style()->borderStart() : style()->borderEnd(); if (sb.style() == BHIDDEN) return -1; if (sb.style() > BHIDDEN) borderWidth = sb.width(); - const BorderValue& rb = lastChild()->style()->borderAfter(); - if (rb.style() == BHIDDEN) - return -1; - if (rb.style() > BHIDDEN && rb.width() > borderWidth) - borderWidth = rb.width(); - - bool allHidden = true; - for (unsigned c = 0; c < totalCols; c++) { - const CellStruct& current = cellAt(m_grid.size() - 1, c); - if (current.inColSpan || !current.hasCells()) - continue; - const BorderValue& cb = current.primaryCell()->style()->borderAfter(); // FIXME: Make this work with perpendicular and flipped cells. - // FIXME: Don't repeat for the same col group - RenderTableCol* colGroup = table()->colElement(c); - if (colGroup) { - const BorderValue& gb = colGroup->style()->borderAfter(); - if (gb.style() == BHIDDEN || cb.style() == BHIDDEN) - continue; - allHidden = false; - if (gb.style() > BHIDDEN && gb.width() > borderWidth) - borderWidth = gb.width(); - if (cb.style() > BHIDDEN && cb.width() > borderWidth) - borderWidth = cb.width(); - } else { - if (cb.style() == BHIDDEN) - continue; - allHidden = false; - if (cb.style() > BHIDDEN && cb.width() > borderWidth) - borderWidth = cb.width(); - } - } - if (allHidden) - return -1; - - return (borderWidth + 1) / 2; -} - -int RenderTableSection::calcOuterBorderStart() const -{ - unsigned totalCols = table()->numEffCols(); - if (!m_grid.size() || !totalCols) - return 0; - - unsigned borderWidth = 0; - - const BorderValue& sb = style()->borderStart(); - if (sb.style() == BHIDDEN) - return -1; - if (sb.style() > BHIDDEN) - borderWidth = sb.width(); - - if (RenderTableCol* colGroup = table()->colElement(0)) { - const BorderValue& gb = colGroup->style()->borderStart(); + if (RenderTableCol* colGroup = table()->colElement(colIndex)) { + const BorderValue& gb = side == BorderStart ? colGroup->style()->borderStart() : colGroup->style()->borderEnd(); if (gb.style() == BHIDDEN) return -1; if (gb.style() > BHIDDEN && gb.width() > borderWidth) @@ -1188,12 +1149,14 @@ int RenderTableSection::calcOuterBorderStart() const bool allHidden = true; for (unsigned r = 0; r < m_grid.size(); r++) { - const CellStruct& current = cellAt(r, 0); + const CellStruct& current = cellAt(r, colIndex); if (!current.hasCells()) continue; // FIXME: Don't repeat for the same cell - const BorderValue& cb = current.primaryCell()->style()->borderStart(); // FIXME: Make this work with perpendicular and flipped cells. - const BorderValue& rb = current.primaryCell()->parent()->style()->borderStart(); + const RenderStyle* primaryCellStyle = current.primaryCell()->style(); + const RenderStyle* primaryCellParentStyle = current.primaryCell()->parent()->style(); + const BorderValue& cb = side == BorderStart ? primaryCellStyle->borderStart() : primaryCellStyle->borderEnd(); // FIXME: Make this work with perpendicular and flipped cells. + const BorderValue& rb = side == BorderStart ? primaryCellParentStyle->borderStart() : primaryCellParentStyle->borderEnd(); if (cb.style() == BHIDDEN || rb.style() == BHIDDEN) continue; allHidden = false; @@ -1205,59 +1168,17 @@ int RenderTableSection::calcOuterBorderStart() const if (allHidden) return -1; - return (borderWidth + (table()->style()->isLeftToRightDirection() ? 0 : 1)) / 2; -} - -int RenderTableSection::calcOuterBorderEnd() const -{ - unsigned totalCols = table()->numEffCols(); - if (!m_grid.size() || !totalCols) - return 0; - - unsigned borderWidth = 0; - - const BorderValue& sb = style()->borderEnd(); - if (sb.style() == BHIDDEN) - return -1; - if (sb.style() > BHIDDEN) - borderWidth = sb.width(); - - if (RenderTableCol* colGroup = table()->colElement(totalCols - 1)) { - const BorderValue& gb = colGroup->style()->borderEnd(); - if (gb.style() == BHIDDEN) - return -1; - if (gb.style() > BHIDDEN && gb.width() > borderWidth) - borderWidth = gb.width(); - } - - bool allHidden = true; - for (unsigned r = 0; r < m_grid.size(); r++) { - const CellStruct& current = cellAt(r, totalCols - 1); - if (!current.hasCells()) - continue; - // FIXME: Don't repeat for the same cell - const BorderValue& cb = current.primaryCell()->style()->borderEnd(); // FIXME: Make this work with perpendicular and flipped cells. - const BorderValue& rb = current.primaryCell()->parent()->style()->borderEnd(); - if (cb.style() == BHIDDEN || rb.style() == BHIDDEN) - continue; - allHidden = false; - if (cb.style() > BHIDDEN && cb.width() > borderWidth) - borderWidth = cb.width(); - if (rb.style() > BHIDDEN && rb.width() > borderWidth) - borderWidth = rb.width(); - } - if (allHidden) - return -1; - - return (borderWidth + (table()->style()->isLeftToRightDirection() ? 1 : 0)) / 2; + if ((side == BorderStart) != table()->style()->isLeftToRightDirection()) + borderWidth++; // Distribute rounding error + return borderWidth / 2; } void RenderTableSection::recalcOuterBorder() { - m_outerBorderBefore = calcOuterBorderBefore(); - m_outerBorderAfter = calcOuterBorderAfter(); - m_outerBorderStart = calcOuterBorderStart(); - m_outerBorderEnd = calcOuterBorderEnd(); + m_outerBorderBefore = calcBlockDirectionOuterBorder(BorderBefore); + m_outerBorderAfter = calcBlockDirectionOuterBorder(BorderAfter); + m_outerBorderStart = calcInlineDirectionOuterBorder(BorderStart); + m_outerBorderEnd = calcInlineDirectionOuterBorder(BorderEnd); } int RenderTableSection::firstLineBoxBaseline() const @@ -1286,7 +1207,7 @@ void RenderTableSection::paint(PaintInfo& paintInfo, const LayoutPoint& paintOff { ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this); - ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout()); + ASSERT(!needsLayout()); // avoid crashing on bugs that cause us to paint with dirty layout if (needsLayout()) return; @@ -1463,11 +1384,8 @@ CellSpan RenderTableSection::spannedColumns(const LayoutRect& flippedRect) const void RenderTableSection::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - PaintPhase paintPhase = paintInfo.phase; - LayoutRect localRepaintRect = paintInfo.rect; localRepaintRect.moveBy(-paintOffset); - localRepaintRect.inflate(maximalOutlineSize(paintPhase)); LayoutRect tableAlignedRect = logicalRectForWritingModeAndDirection(localRepaintRect); @@ -1564,7 +1482,7 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, const LayoutPoint& pa void RenderTableSection::imageChanged(WrappedImagePtr, const IntRect*) { // FIXME: Examine cells and repaint only the rect the image paints in. - repaint(); + paintInvalidationForWholeRenderer(); } void RenderTableSection::recalcCells() @@ -1579,30 +1497,22 @@ void RenderTableSection::recalcCells() m_cRow = 0; m_grid.clear(); - for (RenderObject* row = firstChild(); row; row = row->nextSibling()) { - if (row->isTableRow()) { - unsigned insertionRow = m_cRow; - m_cRow++; - m_cCol = 0; - ensureRows(m_cRow); - - RenderTableRow* tableRow = toRenderTableRow(row); - m_grid[insertionRow].rowRenderer = tableRow; - tableRow->setRowIndex(insertionRow); - setRowLogicalHeightToRowStyleLogicalHeight(m_grid[insertionRow]); + for (RenderTableRow* row = firstRow(); row; row = row->nextRow()) { + unsigned insertionRow = m_cRow; + ++m_cRow; + m_cCol = 0; + ensureRows(m_cRow); - for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) { - if (!cell->isTableCell()) - continue; + m_grid[insertionRow].rowRenderer = row; + row->setRowIndex(insertionRow); + setRowLogicalHeightToRowStyleLogicalHeight(m_grid[insertionRow]); - RenderTableCell* tableCell = toRenderTableCell(cell); - addCell(tableCell, tableRow); - } - } + for (RenderTableCell* cell = row->firstCell(); cell; cell = cell->nextCell()) + addCell(cell, row); } m_grid.shrinkToFit(); - setNeedsLayout(); + setNeedsLayoutAndFullPaintInvalidation(); } // FIXME: This function could be made O(1) in certain cases (like for the non-most-constrainive cells' case). @@ -1613,12 +1523,8 @@ void RenderTableSection::rowLogicalHeightChanged(unsigned rowIndex) setRowLogicalHeightToRowStyleLogicalHeight(m_grid[rowIndex]); - for (RenderObject* cell = m_grid[rowIndex].rowRenderer->firstChild(); cell; cell = cell->nextSibling()) { - if (!cell->isTableCell()) - continue; - - updateLogicalHeightForCell(m_grid[rowIndex], toRenderTableCell(cell)); - } + for (RenderTableCell* cell = m_grid[rowIndex].rowRenderer->firstCell(); cell; cell = cell->nextCell()) + updateLogicalHeightForCell(m_grid[rowIndex], cell); } void RenderTableSection::setNeedsCellRecalc() @@ -1685,7 +1591,7 @@ void RenderTableSection::splitColumn(unsigned pos, unsigned first) Row& r = m_grid[row].row; r.insert(pos + 1, CellStruct()); if (r[pos].hasCells()) { - r[pos + 1].cells.append(r[pos].cells); + r[pos + 1].cells.appendVector(r[pos].cells); RenderTableCell* cell = r[pos].primaryCell(); ASSERT(cell); ASSERT(cell->colSpan() >= (r[pos].inColSpan ? 1u : 0)); @@ -1704,25 +1610,25 @@ void RenderTableSection::splitColumn(unsigned pos, unsigned first) bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) { // If we have no children then we have nothing to do. - if (!firstChild()) + if (!firstRow()) return false; // Table sections cannot ever be hit tested. Effectively they do not exist. // Just forward to our children always. LayoutPoint adjustedLocation = accumulatedOffset + location(); - if (hasOverflowClip() && !locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region()))) + if (hasOverflowClip() && !locationInContainer.intersects(overflowClipRect(adjustedLocation))) return false; if (hasOverflowingCell()) { - for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { + for (RenderTableRow* row = lastRow(); row; row = row->previousRow()) { // FIXME: We have to skip over inline flows, since they can show up inside table rows // at the moment (a demoted inline <form> for example). If we ever implement a // table-specific hit-test method (which we should do for performance reasons anyway), // then we can remove this check. - if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer()) { - LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), adjustedLocation); - if (child->nodeAtPoint(request, result, locationInContainer, childPoint, action)) { + if (!row->hasSelfPaintingLayer()) { + LayoutPoint childPoint = flipForWritingModeForChild(row, adjustedLocation); + if (row->nodeAtPoint(request, result, locationInContainer, childPoint, action)) { updateHitTestResult(result, toLayoutPoint(locationInContainer.point() - childPoint)); return true; } @@ -1814,7 +1720,9 @@ void RenderTableSection::setLogicalPositionForCell(RenderTableCell* cell, unsign cellLocation.setX(table()->columnPositions()[effectiveColumn] + horizontalBorderSpacing); cell->setLogicalLocation(cellLocation); - view()->addLayoutDelta(oldCellLocation - cell->location()); + + if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + view()->addLayoutDelta(oldCellLocation - cell->location()); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTableSection.h b/chromium/third_party/WebKit/Source/core/rendering/RenderTableSection.h index 42b51ec6b3e..27410d5b14e 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTableSection.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTableSection.h @@ -4,7 +4,7 @@ * (C) 1998 Waldo Bastian (bastian@kde.org) * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2009, 2013 Apple Inc. 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 @@ -65,13 +65,13 @@ public: RenderTableSection(Element*); virtual ~RenderTableSection(); - RenderObject* firstChild() const { ASSERT(children() == virtualChildren()); return children()->firstChild(); } - RenderObject* lastChild() const { ASSERT(children() == virtualChildren()); return children()->lastChild(); } + RenderTableRow* firstRow() const; + RenderTableRow* lastRow() const; const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } - virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); + virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE; virtual int firstLineBoxBaseline() const OVERRIDE; @@ -129,14 +129,14 @@ public: SpanningRowsHeight() : totalRowsHeight(0) , spanningCellHeightIgnoringBorderSpacing(0) - , rowWithOnlySpanningCells(false) + , isAnyRowWithOnlySpanningCells(false) { } Vector<int> rowHeight; int totalRowsHeight; int spanningCellHeightIgnoringBorderSpacing; - bool rowWithOnlySpanningCells; + bool isAnyRowWithOnlySpanningCells; }; const BorderValue& borderAdjoiningTableStart() const @@ -174,10 +174,10 @@ public: void appendColumn(unsigned pos); void splitColumn(unsigned pos, unsigned first); - int calcOuterBorderBefore() const; - int calcOuterBorderAfter() const; - int calcOuterBorderStart() const; - int calcOuterBorderEnd() const; + enum BlockBorderSide { BorderBefore, BorderAfter }; + int calcBlockDirectionOuterBorder(BlockBorderSide) const; + enum InlineBorderSide { BorderStart, BorderEnd }; + int calcInlineDirectionOuterBorder(InlineBorderSide) const; void recalcOuterBorder(); int outerBorderBefore() const { return m_outerBorderBefore; } @@ -218,26 +218,25 @@ public: virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; protected: - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; private: - virtual RenderObjectChildList* virtualChildren() { return children(); } - virtual const RenderObjectChildList* virtualChildren() const { return children(); } + virtual RenderObjectChildList* virtualChildren() OVERRIDE { return children(); } + virtual const RenderObjectChildList* virtualChildren() const OVERRIDE { return children(); } - virtual const char* renderName() const { return (isAnonymous() || isPseudoElement()) ? "RenderTableSection (anonymous)" : "RenderTableSection"; } + virtual const char* renderName() const OVERRIDE { return (isAnonymous() || isPseudoElement()) ? "RenderTableSection (anonymous)" : "RenderTableSection"; } - virtual bool isTableSection() const { return true; } + virtual bool isTableSection() const OVERRIDE { return true; } virtual void willBeRemovedFromTree() OVERRIDE; - virtual void layout(); - - virtual void paintCell(RenderTableCell*, PaintInfo&, const LayoutPoint&); - virtual void paintObject(PaintInfo&, const LayoutPoint&); + virtual void layout() OVERRIDE; - virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + void paintCell(RenderTableCell*, PaintInfo&, const LayoutPoint&); + virtual void paintObject(PaintInfo&, const LayoutPoint&) OVERRIDE; - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) OVERRIDE; int borderSpacingForRow(unsigned row) const { return m_grid[row].rowRenderer ? table()->vBorderSpacing() : 0; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderText.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderText.cpp index b89ddc756ba..64fa967bd38 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderText.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderText.cpp @@ -28,9 +28,9 @@ #include "core/accessibility/AXObjectCache.h" #include "core/dom/Text.h" #include "core/editing/TextIterator.h" -#include "core/fetch/TextResourceDecoder.h" #include "core/frame/FrameView.h" #include "core/frame/Settings.h" +#include "core/html/parser/TextResourceDecoder.h" #include "core/rendering/AbstractInlineTextBox.h" #include "core/rendering/EllipsisBox.h" #include "core/rendering/InlineTextBox.h" @@ -39,8 +39,12 @@ #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderView.h" #include "core/rendering/break_lines.h" +#include "platform/fonts/Character.h" +#include "platform/fonts/FontCache.h" #include "platform/geometry/FloatQuad.h" +#include "platform/text/BidiResolver.h" #include "platform/text/TextBreakIterator.h" +#include "platform/text/TextRunIterator.h" #include "wtf/text/StringBuffer.h" #include "wtf/text/StringBuilder.h" #include "wtf/unicode/CharacterNames.h" @@ -64,7 +68,7 @@ class SecureTextTimer; typedef HashMap<RenderText*, SecureTextTimer*> SecureTextTimerMap; static SecureTextTimerMap* gSecureTextTimers = 0; -class SecureTextTimer : public TimerBase { +class SecureTextTimer FINAL : public TimerBase { public: SecureTextTimer(RenderText* renderText) : m_renderText(renderText) @@ -76,13 +80,13 @@ public: { m_lastTypedCharacterOffset = lastTypedCharacterOffset; if (Settings* settings = m_renderText->document().settings()) - startOneShot(settings->passwordEchoDurationInSeconds()); + startOneShot(settings->passwordEchoDurationInSeconds(), FROM_HERE); } void invalidate() { m_lastTypedCharacterOffset = -1; } unsigned lastTypedCharacterOffset() { return m_lastTypedCharacterOffset; } private: - virtual void fired() + virtual void fired() OVERRIDE { ASSERT(gSecureTextTimers->contains(m_renderText)); m_renderText->setText(m_renderText->text().impl(), true /* forcing setting text as it may be masked later */); @@ -190,8 +194,8 @@ void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyl // we already did this for the parent of the text run. // We do have to schedule layouts, though, since a style change can force us to // need to relayout. - if (diff == StyleDifferenceLayout) { - setNeedsLayoutAndPrefWidthsRecalc(); + if (diff.needsFullLayout()) { + setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); m_knownToHaveNoOverflowAndNoFallbackFonts = false; } @@ -201,8 +205,11 @@ void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyl if (oldTransform != newStyle->textTransform() || oldSecurity != newStyle->textSecurity()) transformText(); + // This is an optimization that kicks off font load before layout. + // In order to make it fast, we only check if the first character of the + // text is included in the unicode ranges of the fonts. if (!text().containsOnlyWhitespace()) - newStyle->font().willUseFontData(); + newStyle->font().willUseFontData(text().characterStartingAt(0)); } void RenderText::removeAndDestroyTextBoxes() @@ -210,7 +217,7 @@ void RenderText::removeAndDestroyTextBoxes() if (!documentBeingDestroyed()) { if (firstTextBox()) { if (isBR()) { - RootInlineBox* next = firstTextBox()->root()->nextRootBox(); + RootInlineBox* next = firstTextBox()->root().nextRootBox(); if (next) next->markDirty(); } @@ -362,11 +369,11 @@ void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, u if (useSelectionHeight) { LayoutRect selectionRect = box->localSelectionRect(start, end); if (box->isHorizontal()) { - r.setHeight(selectionRect.height()); - r.setY(selectionRect.y()); + r.setHeight(selectionRect.height().toFloat()); + r.setY(selectionRect.y().toFloat()); } else { - r.setWidth(selectionRect.width()); - r.setX(selectionRect.x()); + r.setWidth(selectionRect.width().toFloat()); + r.setX(selectionRect.x().toFloat()); } } rects.append(localToAbsoluteQuad(r, 0, wasFixed).enclosingBoundingBox()); @@ -389,7 +396,7 @@ static IntRect ellipsisRectForBox(InlineTextBox* box, unsigned startPos, unsigne return IntRect(); IntRect rect; - if (EllipsisBox* ellipsis = box->root()->ellipsisBox()) { + if (EllipsisBox* ellipsis = box->root().ellipsisBox()) { int ellipsisStartPosition = max<int>(startPos - box->start(), 0); int ellipsisEndPosition = min<int>(endPos - box->start(), box->len()); @@ -445,11 +452,11 @@ void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, if (useSelectionHeight) { LayoutRect selectionRect = box->localSelectionRect(start, end); if (box->isHorizontal()) { - r.setHeight(selectionRect.height()); - r.setY(selectionRect.y()); + r.setHeight(selectionRect.height().toFloat()); + r.setY(selectionRect.y().toFloat()); } else { - r.setWidth(selectionRect.width()); - r.setX(selectionRect.x()); + r.setWidth(selectionRect.width().toFloat()); + r.setX(selectionRect.x().toFloat()); } } quads.append(localToAbsoluteQuad(r, 0, wasFixed)); @@ -461,27 +468,6 @@ void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, } } -InlineTextBox* RenderText::findNextInlineTextBox(int offset, int& pos) const -{ - // The text runs point to parts of the RenderText's m_text - // (they don't include '\n') - // Find the text run that includes the character at offset - // and return pos, which is the position of the char in the run. - - if (!m_firstTextBox) - return 0; - - InlineTextBox* s = m_firstTextBox; - int off = s->len(); - while (offset > off && s->nextTextBox()) { - s = s->nextTextBox(); - off = s->start() + s->len(); - } - // we are now in the correct text run - pos = (offset > off ? s->len() : s->len() - (off - offset) ); - return s; -} - enum ShouldAffinityBeDownstream { AlwaysDownstream, AlwaysUpstream, UpstreamIfPositionIsNotAtStart }; static bool lineDirectionPointFitsInBox(int pointLineDirection, InlineTextBox* box, ShouldAffinityBeDownstream& shouldAffinityBeDownstream) @@ -533,14 +519,13 @@ static PositionWithAffinity createPositionWithAffinityForBox(const InlineBox* bo affinity = offset > box->caretMinOffset() ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM; break; } - int textStartOffset = box->renderer()->isText() ? toRenderText(box->renderer())->textStartOffset() : 0; - return box->renderer()->createPositionWithAffinity(offset + textStartOffset, affinity); + int textStartOffset = box->renderer().isText() ? toRenderText(box->renderer()).textStartOffset() : 0; + return box->renderer().createPositionWithAffinity(offset + textStartOffset, affinity); } static PositionWithAffinity createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(const InlineTextBox* box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream) { ASSERT(box); - ASSERT(box->renderer()); ASSERT(offset >= 0); if (offset && static_cast<unsigned>(offset) < box->len()) @@ -552,7 +537,7 @@ static PositionWithAffinity createPositionWithAffinityForBoxAfterAdjustingOffset const InlineBox* prevBox = box->prevLeafChildIgnoringLineBreak(); if ((prevBox && prevBox->bidiLevel() == box->bidiLevel()) - || box->renderer()->containingBlock()->style()->direction() == box->direction()) // FIXME: left on 12CBA + || box->renderer().containingBlock()->style()->direction() == box->direction()) // FIXME: left on 12CBA return createPositionWithAffinityForBox(box, box->caretLeftmostOffset(), shouldAffinityBeDownstream); if (prevBox && prevBox->bidiLevel() > box->bidiLevel()) { @@ -582,7 +567,7 @@ static PositionWithAffinity createPositionWithAffinityForBoxAfterAdjustingOffset const InlineBox* nextBox = box->nextLeafChildIgnoringLineBreak(); if ((nextBox && nextBox->bidiLevel() == box->bidiLevel()) - || box->renderer()->containingBlock()->style()->direction() == box->direction()) + || box->renderer().containingBlock()->style()->direction() == box->direction()) return createPositionWithAffinityForBox(box, box->caretRightmostOffset(), shouldAffinityBeDownstream); // offset is on the right edge @@ -625,17 +610,17 @@ PositionWithAffinity RenderText::positionForPoint(const LayoutPoint& point) if (box->isLineBreak() && !box->prevLeafChild() && box->nextLeafChild() && !box->nextLeafChild()->isLineBreak()) box = box->nextTextBox(); - RootInlineBox* rootBox = box->root(); - LayoutUnit top = min(rootBox->selectionTop(), rootBox->lineTop()); + RootInlineBox& rootBox = box->root(); + LayoutUnit top = min(rootBox.selectionTop(), rootBox.lineTop()); if (pointBlockDirection > top || (!blocksAreFlipped && pointBlockDirection == top)) { - LayoutUnit bottom = rootBox->selectionBottom(); - if (rootBox->nextRootBox()) - bottom = min(bottom, rootBox->nextRootBox()->lineTop()); + LayoutUnit bottom = rootBox.selectionBottom(); + if (rootBox.nextRootBox()) + bottom = min(bottom, rootBox.nextRootBox()->lineTop()); if (pointBlockDirection < bottom || (blocksAreFlipped && pointBlockDirection == bottom)) { ShouldAffinityBeDownstream shouldAffinityBeDownstream; if (lineDirectionPointFitsInBox(pointLineDirection, box, shouldAffinityBeDownstream)) - return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(box, box->offsetForPosition(pointLineDirection), shouldAffinityBeDownstream); + return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(box, box->offsetForPosition(pointLineDirection.toFloat()), shouldAffinityBeDownstream); } } lastBox = box; @@ -644,7 +629,7 @@ PositionWithAffinity RenderText::positionForPoint(const LayoutPoint& point) if (lastBox) { ShouldAffinityBeDownstream shouldAffinityBeDownstream; lineDirectionPointFitsInBox(pointLineDirection, lastBox, shouldAffinityBeDownstream); - return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(lastBox, lastBox->offsetForPosition(pointLineDirection) + lastBox->start(), shouldAffinityBeDownstream); + return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(lastBox, lastBox->offsetForPosition(pointLineDirection.toFloat()) + lastBox->start(), shouldAffinityBeDownstream); } return createPositionWithAffinity(0, DOWNSTREAM); } @@ -660,8 +645,8 @@ LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, Lay InlineTextBox* box = toInlineTextBox(inlineBox); - int height = box->root()->selectionHeight(); - int top = box->root()->selectionTop(); + int height = box->root().selectionHeight(); + int top = box->root().selectionTop(); // Go ahead and round left to snap it to the nearest pixel. float left = box->positionForOffset(caretOffset); @@ -673,13 +658,13 @@ LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, Lay left = roundf(left); - float rootLeft = box->root()->logicalLeft(); - float rootRight = box->root()->logicalRight(); + float rootLeft = box->root().logicalLeft(); + float rootRight = box->root().logicalRight(); // FIXME: should we use the width of the root inline box or the // width of the containing block for this? if (extraWidthToEndOfLine) - *extraWidthToEndOfLine = (box->root()->logicalWidth() + rootLeft) - (left + 1); + *extraWidthToEndOfLine = (box->root().logicalWidth() + rootLeft) - (left + 1); RenderBlock* cb = containingBlock(); RenderStyle* cbStyle = cb->style(); @@ -687,7 +672,7 @@ LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, Lay float leftEdge; float rightEdge; leftEdge = min<float>(0, rootLeft); - rightEdge = max<float>(cb->logicalWidth(), rootRight); + rightEdge = max<float>(cb->logicalWidth().toFloat(), rootRight); bool rightAligned = false; switch (cbStyle->textAlign()) { @@ -720,7 +705,7 @@ LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, Lay return style()->isHorizontalWritingMode() ? IntRect(left, top, caretWidth, height) : IntRect(top, left, height, caretWidth); } -ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len, float xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const +ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len, float xPos, TextDirection textDirection, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { if (style()->hasTextCombine() && isCombineText()) { const RenderCombineText* combineText = toRenderCombineText(this); @@ -728,7 +713,7 @@ ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len return combineText->combinedTextWidth(f); } - if (f.isFixedPitch() && !f.isSmallCaps() && m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) { + if (f.isFixedPitch() && f.fontDescription().variant() == FontVariantNormal && m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) { float monospaceCharacterWidth = f.spaceWidth(); float w = 0; bool isSpace; @@ -755,18 +740,19 @@ ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len isSpace = false; } if (isSpace && i > start) - w += f.wordSpacing(); + w += f.fontDescription().wordSpacing(); } return w; } - TextRun run = RenderBlockFlow::constructTextRun(const_cast<RenderText*>(this), f, this, start, len, style()); + TextRun run = RenderBlockFlow::constructTextRun(const_cast<RenderText*>(this), f, this, start, len, style(), textDirection); run.setCharactersLength(textLength() - start); ASSERT(run.charactersLength() >= run.length()); run.setCharacterScanForCodePath(!canUseSimpleFontCodePath()); run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize()); run.setXPos(xPos); + FontCachePurgePreventer fontCachePurgePreventer; return f.width(run, fallbackFonts, glyphOverflow); } @@ -775,7 +761,8 @@ void RenderText::trimmedPrefWidths(float leadWidth, float& lastLineMinWidth, bool& hasBreakableEnd, bool& hasBreakableChar, bool& hasBreak, float& firstLineMaxWidth, float& lastLineMaxWidth, - float& minWidth, float& maxWidth, bool& stripFrontSpaces) + float& minWidth, float& maxWidth, bool& stripFrontSpaces, + TextDirection direction) { bool collapseWhiteSpace = style()->collapseWhiteSpace(); if (!collapseWhiteSpace) @@ -815,10 +802,10 @@ void RenderText::trimmedPrefWidths(float leadWidth, const Font& font = style()->font(); // FIXME: This ignores first-line. if (stripFrontSpaces) { const UChar space = ' '; - float spaceWidth = font.width(RenderBlockFlow::constructTextRun(this, font, &space, 1, style())); + float spaceWidth = font.width(RenderBlockFlow::constructTextRun(this, font, &space, 1, style(), direction)); maxWidth -= spaceWidth; } else { - maxWidth += font.wordSpacing(); + maxWidth += font.fontDescription().wordSpacing(); } } @@ -839,7 +826,7 @@ void RenderText::trimmedPrefWidths(float leadWidth, linelen++; if (linelen) { - lastLineMaxWidth = widthFromCache(f, i, linelen, leadWidth + lastLineMaxWidth, 0, 0); + lastLineMaxWidth = widthFromCache(f, i, linelen, leadWidth + lastLineMaxWidth, direction, 0, 0); if (firstLine) { firstLine = false; leadWidth = 0; @@ -886,10 +873,10 @@ void RenderText::computePreferredLogicalWidths(float leadWidth) m_knownToHaveNoOverflowAndNoFallbackFonts = true; } -static inline float hyphenWidth(RenderText* renderer, const Font& font) +static inline float hyphenWidth(RenderText* renderer, const Font& font, TextDirection direction) { RenderStyle* style = renderer->style(); - return font.width(RenderBlockFlow::constructTextRun(renderer, font, style->hyphenString().string(), style)); + return font.width(RenderBlockFlow::constructTextRun(renderer, font, style->hyphenString().string(), style, direction)); } void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow) @@ -925,23 +912,47 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si bool firstLine = true; int nextBreakable = -1; int lastWordBoundary = 0; + float cachedWordTrailingSpaceWidth[2] = { 0, 0 }; // LTR, RTL - // Non-zero only when kerning is enabled, in which case we measure words with their trailing - // space, then subtract its width. - float wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.width(RenderBlockFlow::constructTextRun(this, f, &space, 1, styleToUse)) + wordSpacing : 0; - - // If automatic hyphenation is allowed, we keep track of the width of the widest word (or word - // fragment) encountered so far, and only try hyphenating words that are wider. - float maxWordWidth = numeric_limits<float>::max(); int firstGlyphLeftOverflow = -1; bool breakAll = (styleToUse->wordBreak() == BreakAllWordBreak || styleToUse->wordBreak() == BreakWordBreak) && styleToUse->autoWrap(); + TextRun textRun(text()); + BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver; + + BidiCharacterRun* run; + TextDirection textDirection = styleToUse->direction(); + if (isOverride(styleToUse->unicodeBidi())) { + run = 0; + } else { + BidiStatus status(LTR, false); + status.last = status.lastStrong = WTF::Unicode::OtherNeutral; + bidiResolver.setStatus(status); + bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&textRun, 0)); + bool hardLineBreak = false; + bool reorderRuns = false; + bidiResolver.createBidiRunsForLine(TextRunIterator(&textRun, textRun.length()), NoVisualOverride, hardLineBreak, reorderRuns); + BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs(); + run = bidiRuns.firstRun(); + } + for (int i = 0; i < len; i++) { UChar c = uncheckedCharacterAt(i); - bool previousCharacterIsSpace = isSpace; + if (run) { + // Treat adjacent runs with the same resolved directionality + // (TextDirection as opposed to WTF::Unicode::Direction) as belonging + // to the same run to avoid breaking unnecessarily. + while (i > run->stop() || (run->next() && run->next()->direction() == run->direction())) + run = run->next(); + ASSERT(run); + ASSERT(i <= run->stop()); + textDirection = run->direction(); + } + + bool previousCharacterIsSpace = isSpace; bool isNewline = false; if (c == '\n') { if (styleToUse->preserveNewline()) { @@ -979,7 +990,7 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si lastWordBoundary++; continue; } else if (c == softHyphen) { - currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow); + currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow); if (firstGlyphLeftOverflow < 0) firstGlyphLeftOverflow = glyphOverflow.left; lastWordBoundary = i + 1; @@ -1002,20 +1013,32 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si } } + // Terminate word boundary at bidi run boundary. + if (run) + j = min(j, run->stop() + 1); int wordLen = j - i; if (wordLen) { bool isSpace = (j < len) && c == ' '; + + // Non-zero only when kerning is enabled, in which case we measure words with their trailing + // space, then subtract its width. + float wordTrailingSpaceWidth = 0; + if (isSpace && (f.fontDescription().typesettingFeatures() & Kerning)) { + ASSERT(textDirection >=0 && textDirection <= 1); + if (!cachedWordTrailingSpaceWidth[textDirection]) + cachedWordTrailingSpaceWidth[textDirection] = f.width(RenderBlockFlow::constructTextRun(this, f, &space, 1, styleToUse, textDirection)) + wordSpacing; + wordTrailingSpaceWidth = cachedWordTrailingSpaceWidth[textDirection]; + } + float w; if (wordTrailingSpaceWidth && isSpace) - w = widthFromCache(f, i, wordLen + 1, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow) - wordTrailingSpaceWidth; + w = widthFromCache(f, i, wordLen + 1, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow) - wordTrailingSpaceWidth; else { - w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow); + w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow); if (c == softHyphen) - currMinWidth += hyphenWidth(this, f); + currMinWidth += hyphenWidth(this, f, textDirection); } - maxWordWidth = max(maxWordWidth, w); - if (firstGlyphLeftOverflow < 0) firstGlyphLeftOverflow = glyphOverflow.left; currMinWidth += w; @@ -1023,7 +1046,7 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si if (lastWordBoundary == i) currMaxWidth += w; else - currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow); + currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow); lastWordBoundary = j; } @@ -1074,7 +1097,7 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si m_maxWidth = currMaxWidth; currMaxWidth = 0; } else { - TextRun run = RenderBlockFlow::constructTextRun(this, f, this, i, 1, styleToUse); + TextRun run = RenderBlockFlow::constructTextRun(this, f, this, i, 1, styleToUse, textDirection); run.setCharactersLength(len - i); ASSERT(run.charactersLength() >= run.length()); run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize()); @@ -1088,6 +1111,8 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si lastWordBoundary++; } } + if (run) + bidiResolver.runs().deleteRuns(); if (firstGlyphLeftOverflow > 0) glyphOverflow.left = firstGlyphLeftOverflow; @@ -1172,16 +1197,12 @@ void RenderText::setSelectionState(SelectionState state) for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { if (box->isSelected(startPos, endPos)) { - RootInlineBox* root = box->root(); - if (root) - root->setHasSelectedChildren(true); + box->root().setHasSelectedChildren(true); } } } else { for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { - RootInlineBox* root = box->root(); - if (root) - root->setHasSelectedChildren(state == SelectionInside); + box->root().setHasSelectedChildren(state == SelectionInside); } } } @@ -1217,7 +1238,7 @@ void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, // Text run is entirely after the affected range. if (curr->start() > end) { curr->offsetRun(delta); - RootInlineBox* root = curr->root(); + RootInlineBox* root = &curr->root(); if (!firstRootBox) { firstRootBox = root; // The affected area was in between two runs. Go ahead and mark the root box of @@ -1251,7 +1272,7 @@ void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, firstRootBox = prev; } else if (lastTextBox()) { ASSERT(!lastRootBox); - firstRootBox = lastTextBox()->root(); + firstRootBox = &lastTextBox()->root(); firstRootBox->markDirty(); dirtiedLines = true; } @@ -1385,7 +1406,11 @@ void RenderText::setText(PassRefPtr<StringImpl> text, bool force) return; setTextInternal(text); - setNeedsLayoutAndPrefWidthsRecalc(); + // If preferredLogicalWidthsDirty() of an orphan child is true, RenderObjectChildList:: + // insertChildNode() fails to set true to owner. To avoid that, we call + // setNeedsLayoutAndPrefWidthsRecalc() only if this RenderText has parent. + if (parent()) + setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); m_knownToHaveNoOverflowAndNoFallbackFonts = false; if (AXObjectCache* cache = document().existingAXObjectCache()) @@ -1405,7 +1430,7 @@ void RenderText::dirtyLineBoxes(bool fullLayout) InlineTextBox* RenderText::createTextBox() { - return new InlineTextBox(this); + return new InlineTextBox(*this); } InlineTextBox* RenderText::createInlineTextBox() @@ -1429,7 +1454,7 @@ void RenderText::positionLineBox(InlineBox* box) // FIXME: should not be needed!!! if (!s->len()) { // We want the box to be destroyed. - s->remove(); + s->remove(DontMarkLineBoxes); if (m_firstTextBox == s) m_firstTextBox = s->nextTextBox(); else @@ -1445,7 +1470,7 @@ void RenderText::positionLineBox(InlineBox* box) m_containsReversedText |= !s->isLeftToRightDirection(); } -float RenderText::width(unsigned from, unsigned len, float xPos, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const +float RenderText::width(unsigned from, unsigned len, float xPos, TextDirection textDirection, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { if (from >= textLength()) return 0; @@ -1453,10 +1478,10 @@ float RenderText::width(unsigned from, unsigned len, float xPos, bool firstLine, if (from + len > textLength()) len = textLength() - from; - return width(from, len, style(firstLine)->font(), xPos, fallbackFonts, glyphOverflow); + return width(from, len, style(firstLine)->font(), xPos, textDirection, fallbackFonts, glyphOverflow); } -float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const +float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos, TextDirection textDirection, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { ASSERT(from + len <= textLength()); if (!textLength()) @@ -1473,12 +1498,14 @@ float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos, m_knownToHaveNoOverflowAndNoFallbackFonts = true; } w = m_maxWidth; - } else + } else { w = maxLogicalWidth(); - } else - w = widthFromCache(f, from, len, xPos, fallbackFonts, glyphOverflow); + } + } else { + w = widthFromCache(f, from, len, xPos, textDirection, fallbackFonts, glyphOverflow); + } } else { - TextRun run = RenderBlockFlow::constructTextRun(const_cast<RenderText*>(this), f, this, from, len, style()); + TextRun run = RenderBlockFlow::constructTextRun(const_cast<RenderText*>(this), f, this, from, len, style(), textDirection); run.setCharactersLength(textLength() - from); ASSERT(run.charactersLength() >= run.length()); @@ -1542,7 +1569,7 @@ LayoutRect RenderText::linesVisualOverflowBoundingBox() const return rect; } -LayoutRect RenderText::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const +LayoutRect RenderText::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const { RenderObject* rendererToRepaint = containingBlock(); @@ -1551,14 +1578,14 @@ LayoutRect RenderText::clippedOverflowRectForRepaint(const RenderLayerModelObjec if (enclosingLayerRenderer != rendererToRepaint && !rendererToRepaint->isDescendantOf(enclosingLayerRenderer)) rendererToRepaint = enclosingLayerRenderer; - // The renderer we chose to repaint may be an ancestor of repaintContainer, but we need to do a repaintContainer-relative repaint. - if (repaintContainer && repaintContainer != rendererToRepaint && !rendererToRepaint->isDescendantOf(repaintContainer)) - return repaintContainer->clippedOverflowRectForRepaint(repaintContainer); + // The renderer we chose to repaint may be an ancestor of paintInvalidationContainer, but we need to do a paintInvalidationContainer-relative repaint. + if (paintInvalidationContainer && paintInvalidationContainer != rendererToRepaint && !rendererToRepaint->isDescendantOf(paintInvalidationContainer)) + return paintInvalidationContainer->clippedOverflowRectForPaintInvalidation(paintInvalidationContainer); - return rendererToRepaint->clippedOverflowRectForRepaint(repaintContainer); + return rendererToRepaint->clippedOverflowRectForPaintInvalidation(paintInvalidationContainer); } -LayoutRect RenderText::selectionRectForRepaint(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent) +LayoutRect RenderText::selectionRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, bool clipToVisibleContent) { ASSERT(!needsLayout()); @@ -1593,12 +1620,12 @@ LayoutRect RenderText::selectionRectForRepaint(const RenderLayerModelObject* rep } if (clipToVisibleContent) - computeRectForRepaint(repaintContainer, rect); + mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect); else { if (cb->hasColumns()) cb->adjustRectForColumns(rect); - rect = localToContainerQuad(FloatRect(rect), repaintContainer).enclosingBoundingBox(); + rect = localToContainerQuad(FloatRect(rect), paintInvalidationContainer).enclosingBoundingBox(); } return rect; @@ -1809,7 +1836,7 @@ bool RenderText::computeCanUseSimpleFontCodePath() const { if (isAllASCII() || m_text.is8Bit()) return true; - return Font::characterRangeCodePath(characters16(), length()) == Font::Simple; + return Character::characterRangeCodePath(characters16(), length()) == SimplePath; } #ifndef NDEBUG diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderText.h b/chromium/third_party/WebKit/Source/core/rendering/RenderText.h index 13af4be1c6b..1f3de61ca18 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderText.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderText.h @@ -24,6 +24,8 @@ #define RenderText_h #include "core/rendering/RenderObject.h" +#include "platform/LengthFunctions.h" +#include "platform/text/TextPath.h" #include "wtf/Forward.h" #include "wtf/PassRefPtr.h" @@ -42,7 +44,7 @@ public: virtual ~RenderText(); #endif - virtual const char* renderName() const; + virtual const char* renderName() const OVERRIDE; virtual bool isTextFragment() const; virtual bool isWordBreak() const; @@ -82,8 +84,8 @@ public: unsigned textLength() const { return m_text.length(); } // non virtual implementation of length() void positionLineBox(InlineBox*); - virtual float width(unsigned from, unsigned len, const Font&, float xPos, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; - virtual float width(unsigned from, unsigned len, float xPos, bool firstLine = false, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; + virtual float width(unsigned from, unsigned len, const Font&, float xPos, TextDirection, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; + virtual float width(unsigned from, unsigned len, float xPos, TextDirection, bool firstLine = false, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; float minLogicalWidth() const; float maxLogicalWidth() const; @@ -93,7 +95,8 @@ public: float& lastLineMinWidth, bool& hasBreakableEnd, bool& hasBreakableChar, bool& hasBreak, float& firstLineMaxWidth, float& lastLineMaxWidth, - float& minWidth, float& maxWidth, bool& stripFrontSpaces); + float& minWidth, float& maxWidth, bool& stripFrontSpaces, + TextDirection); virtual IntRect linesBoundingBox() const; LayoutRect linesVisualOverflowBoundingBox() const; @@ -107,21 +110,21 @@ public: virtual void transformText(); - virtual bool canBeSelectionLeaf() const { return true; } + virtual bool canBeSelectionLeaf() const OVERRIDE { return true; } virtual void setSelectionState(SelectionState s) OVERRIDE FINAL; - virtual LayoutRect selectionRectForRepaint(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent = true) OVERRIDE; - virtual LayoutRect localCaretRect(InlineBox*, int caretOffset, LayoutUnit* extraWidthToEndOfLine = 0); + virtual LayoutRect selectionRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, bool clipToVisibleContent = true) OVERRIDE; + virtual LayoutRect localCaretRect(InlineBox*, int caretOffset, LayoutUnit* extraWidthToEndOfLine = 0) OVERRIDE; - LayoutUnit marginLeft() const { return minimumValueForLength(style()->marginLeft(), 0, view()); } - LayoutUnit marginRight() const { return minimumValueForLength(style()->marginRight(), 0, view()); } + LayoutUnit marginLeft() const { return minimumValueForLength(style()->marginLeft(), 0); } + LayoutUnit marginRight() const { return minimumValueForLength(style()->marginRight(), 0); } - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE FINAL; + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const OVERRIDE FINAL; InlineTextBox* firstTextBox() const { return m_firstTextBox; } InlineTextBox* lastTextBox() const { return m_lastTextBox; } - virtual int caretMinOffset() const; - virtual int caretMaxOffset() const; + virtual int caretMinOffset() const OVERRIDE; + virtual int caretMaxOffset() const OVERRIDE; unsigned renderedTextLength() const; virtual int previousOffset(int current) const OVERRIDE FINAL; @@ -133,8 +136,6 @@ public: bool isSecure() const { return style()->textSecurity() != TSNONE; } void momentarilyRevealLastTypedCharacter(unsigned lastTypedCharacterOffset); - InlineTextBox* findNextInlineTextBox(int offset, int& pos) const; - void checkConsistency() const; bool isAllCollapsibleWhitespace() const; @@ -148,10 +149,10 @@ public: protected: virtual void computePreferredLogicalWidths(float leadWidth); - virtual void willBeDestroyed(); + virtual void willBeDestroyed() OVERRIDE; - virtual void styleWillChange(StyleDifference, const RenderStyle*) OVERRIDE FINAL { } - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleWillChange(StyleDifference, const RenderStyle&) OVERRIDE FINAL { } + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; virtual void setTextInternal(PassRefPtr<StringImpl>); virtual UChar previousCharacter() const; @@ -176,7 +177,7 @@ private: void deleteTextBoxes(); bool containsOnlyWhitespace(unsigned from, unsigned len) const; - float widthFromCache(const Font&, int start, int len, float xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow*) const; + float widthFromCache(const Font&, int start, int len, float xPos, TextDirection, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow*) const; bool isAllASCII() const { return m_isAllASCII; } void secureText(UChar mask); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTextControl.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderTextControl.cpp index d420fbff074..81369e99415 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTextControl.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTextControl.cpp @@ -47,9 +47,9 @@ HTMLTextFormControlElement* RenderTextControl::textFormControlElement() const return toHTMLTextFormControlElement(node()); } -HTMLElement* RenderTextControl::innerTextElement() const +HTMLElement* RenderTextControl::innerEditorElement() const { - return textFormControlElement()->innerTextElement(); + return textFormControlElement()->innerEditorElement(); } void RenderTextControl::addChild(RenderObject* newChild, RenderObject* beforeChild) @@ -57,26 +57,26 @@ void RenderTextControl::addChild(RenderObject* newChild, RenderObject* beforeChi // FIXME: This is a terrible hack to get the caret over the placeholder text since it'll // make us paint the placeholder first. (See https://trac.webkit.org/changeset/118733) Node* node = newChild->node(); - if (node && node->isElementNode() && toElement(node)->pseudo() == "-webkit-input-placeholder") - RenderBlock::addChild(newChild, firstChild()); + if (node && node->isElementNode() && toElement(node)->shadowPseudoId() == "-webkit-input-placeholder") + RenderBlockFlow::addChild(newChild, firstChild()); else - RenderBlock::addChild(newChild, beforeChild); + RenderBlockFlow::addChild(newChild, beforeChild); } void RenderTextControl::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - RenderBlock::styleDidChange(diff, oldStyle); - Element* innerText = innerTextElement(); - if (!innerText) + RenderBlockFlow::styleDidChange(diff, oldStyle); + Element* innerEditor = innerEditorElement(); + if (!innerEditor) return; - RenderBlock* innerTextRenderer = toRenderBlock(innerText->renderer()); - if (innerTextRenderer) { + RenderBlock* innerEditorRenderer = toRenderBlock(innerEditor->renderer()); + if (innerEditorRenderer) { // We may have set the width and the height in the old style in layout(). // Reset them now to avoid getting a spurious layout hint. - innerTextRenderer->style()->setHeight(Length()); - innerTextRenderer->style()->setWidth(Length()); - innerTextRenderer->setStyle(createInnerTextStyle(style())); - innerText->setNeedsStyleRecalc(); + innerEditorRenderer->style()->setHeight(Length()); + innerEditorRenderer->style()->setWidth(Length()); + innerEditorRenderer->setStyle(createInnerEditorStyle(style())); + innerEditor->setNeedsStyleRecalc(SubtreeStyleChange); } textFormControlElement()->updatePlaceholderVisibility(false); } @@ -86,7 +86,7 @@ static inline void updateUserModifyProperty(HTMLTextFormControlElement* node, Re style->setUserModify(node->isDisabledOrReadOnly() ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY); } -void RenderTextControl::adjustInnerTextStyle(RenderStyle* textBlockStyle) const +void RenderTextControl::adjustInnerEditorStyle(RenderStyle* textBlockStyle) const { // The inner block, if present, always has its direction set to LTR, // so we need to inherit the direction and unicode-bidi style from the element. @@ -103,21 +103,21 @@ int RenderTextControl::textBlockLogicalHeight() const int RenderTextControl::textBlockLogicalWidth() const { - Element* innerText = innerTextElement(); - ASSERT(innerText); + Element* innerEditor = innerEditorElement(); + ASSERT(innerEditor); LayoutUnit unitWidth = logicalWidth() - borderAndPaddingLogicalWidth(); - if (innerText->renderer()) - unitWidth -= innerText->renderBox()->paddingStart() + innerText->renderBox()->paddingEnd(); + if (innerEditor->renderer()) + unitWidth -= innerEditor->renderBox()->paddingStart() + innerEditor->renderBox()->paddingEnd(); return unitWidth; } void RenderTextControl::updateFromElement() { - Element* innerText = innerTextElement(); - if (innerText && innerText->renderer()) - updateUserModifyProperty(textFormControlElement(), innerText->renderer()->style()); + Element* innerEditor = innerEditorElement(); + if (innerEditor && innerEditor->renderer()) + updateUserModifyProperty(textFormControlElement(), innerEditor->renderer()->style()); } int RenderTextControl::scrollbarThickness() const @@ -128,33 +128,39 @@ int RenderTextControl::scrollbarThickness() const void RenderTextControl::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const { - HTMLElement* innerText = innerTextElement(); - ASSERT(innerText); - if (RenderBox* innerTextBox = innerText->renderBox()) { - LayoutUnit nonContentHeight = innerTextBox->borderAndPaddingHeight() + innerTextBox->marginHeight(); - logicalHeight = computeControlLogicalHeight(innerTextBox->lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes), nonContentHeight) + borderAndPaddingHeight(); + HTMLElement* innerEditor = innerEditorElement(); + ASSERT(innerEditor); + if (RenderBox* innerEditorBox = innerEditor->renderBox()) { + LayoutUnit nonContentHeight = innerEditorBox->borderAndPaddingHeight() + innerEditorBox->marginHeight(); + logicalHeight = computeControlLogicalHeight(innerEditorBox->lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes), nonContentHeight); // We are able to have a horizontal scrollbar if the overflow style is scroll, or if its auto and there's no word wrap. - if ((isHorizontalWritingMode() && (style()->overflowX() == OSCROLL || (style()->overflowX() == OAUTO && innerText->renderer()->style()->overflowWrap() == NormalOverflowWrap))) - || (!isHorizontalWritingMode() && (style()->overflowY() == OSCROLL || (style()->overflowY() == OAUTO && innerText->renderer()->style()->overflowWrap() == NormalOverflowWrap)))) + if ((isHorizontalWritingMode() && (style()->overflowX() == OSCROLL || (style()->overflowX() == OAUTO && innerEditor->renderer()->style()->overflowWrap() == NormalOverflowWrap))) + || (!isHorizontalWritingMode() && (style()->overflowY() == OSCROLL || (style()->overflowY() == OAUTO && innerEditor->renderer()->style()->overflowWrap() == NormalOverflowWrap)))) logicalHeight += scrollbarThickness(); + + // FIXME: The logical height of the inner text box should have been added before calling computeLogicalHeight to + // avoid this hack. + updateIntrinsicContentLogicalHeight(logicalHeight); + + logicalHeight += borderAndPaddingHeight(); } RenderBox::computeLogicalHeight(logicalHeight, logicalTop, computedValues); } -void RenderTextControl::hitInnerTextElement(HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset) +void RenderTextControl::hitInnerEditorElement(HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset) { - HTMLElement* innerText = innerTextElement(); - if (!innerText->renderer()) + HTMLElement* innerEditor = innerEditorElement(); + if (!innerEditor->renderer()) return; LayoutPoint adjustedLocation = accumulatedOffset + location(); - LayoutPoint localPoint = pointInContainer - toLayoutSize(adjustedLocation + innerText->renderBox()->location()); + LayoutPoint localPoint = pointInContainer - toLayoutSize(adjustedLocation + innerEditor->renderBox()->location()); if (hasOverflowClip()) localPoint += scrolledContentOffset(); - result.setInnerNode(innerText); - result.setInnerNonSharedNode(innerText); + result.setInnerNode(innerEditor); + result.setInnerNonSharedNode(innerEditor); result.setLocalPoint(localPoint); } @@ -234,16 +240,16 @@ float RenderTextControl::scaleEmToUnits(int x) const { // This matches the unitsPerEm value for MS Shell Dlg and Courier New from the "head" font table. float unitsPerEm = 2048.0f; - return roundf(style()->font().size() * x / unitsPerEm); + return roundf(style()->font().fontDescription().computedSize() * x / unitsPerEm); } void RenderTextControl::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const { // Use average character width. Matches IE. - AtomicString family = style()->font().family().family(); + AtomicString family = style()->font().fontDescription().family().family(); maxLogicalWidth = preferredContentLogicalWidth(const_cast<RenderTextControl*>(this)->getAvgCharWidth(family)); - if (RenderBox* innerTextRenderBox = innerTextElement()->renderBox()) - maxLogicalWidth += innerTextRenderBox->paddingStart() + innerTextRenderBox->paddingEnd(); + if (RenderBox* innerEditorRenderBox = innerEditorElement()->renderBox()) + maxLogicalWidth += innerEditorRenderBox->paddingStart() + innerEditorRenderBox->paddingEnd(); if (!style()->logicalWidth().isPercent()) minLogicalWidth = maxLogicalWidth; } @@ -254,20 +260,21 @@ void RenderTextControl::computePreferredLogicalWidths() m_minPreferredLogicalWidth = 0; m_maxPreferredLogicalWidth = 0; + RenderStyle* styleToUse = style(); - if (style()->logicalWidth().isFixed() && style()->logicalWidth().value() >= 0) - m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->logicalWidth().value()); + if (styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() >= 0) + m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalWidth().value()); else computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth); - if (style()->logicalMinWidth().isFixed() && style()->logicalMinWidth().value() > 0) { - m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->logicalMinWidth().value())); - m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->logicalMinWidth().value())); + if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) { + m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value())); + m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value())); } - if (style()->logicalMaxWidth().isFixed()) { - m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->logicalMaxWidth().value())); - m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->logicalMaxWidth().value())); + if (styleToUse->logicalMaxWidth().isFixed()) { + m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value())); + m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value())); } LayoutUnit toAdd = borderAndPaddingLogicalWidth(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTextControl.h b/chromium/third_party/WebKit/Source/core/rendering/RenderTextControl.h index 6269af8d7e0..5a0434563aa 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTextControl.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTextControl.h @@ -34,20 +34,21 @@ public: virtual ~RenderTextControl(); HTMLTextFormControlElement* textFormControlElement() const; - virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const = 0; + virtual PassRefPtr<RenderStyle> createInnerEditorStyle(const RenderStyle* startStyle) const = 0; protected: RenderTextControl(HTMLTextFormControlElement*); - // This convenience function should not be made public because innerTextElement may outlive the render tree. - HTMLElement* innerTextElement() const; + // This convenience function should not be made public because + // innerEditorElement may outlive the render tree. + HTMLElement* innerEditorElement() const; int scrollbarThickness() const; - void adjustInnerTextStyle(RenderStyle* textBlockStyle) const; + void adjustInnerEditorStyle(RenderStyle* textBlockStyle) const; - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; - void hitInnerTextElement(HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset); + void hitInnerEditorElement(HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset); int textBlockLogicalWidth() const; int textBlockLogicalHeight() const; @@ -59,9 +60,9 @@ protected: virtual LayoutUnit preferredContentLogicalWidth(float charWidth) const = 0; virtual LayoutUnit computeControlLogicalHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const = 0; - virtual void updateFromElement(); + virtual void updateFromElement() OVERRIDE; virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE; - virtual RenderObject* layoutSpecialExcludedChild(bool relayoutChildren, SubtreeLayoutScope&); + virtual RenderObject* layoutSpecialExcludedChild(bool relayoutChildren, SubtreeLayoutScope&) OVERRIDE; // We need to override this function because we don't want overflow:hidden on an <input> // to affect the baseline calculation. This is necessary because we are an inline-block @@ -69,20 +70,19 @@ protected: virtual int inlineBlockBaseline(LineDirectionMode direction) const OVERRIDE { return lastLineBoxBaseline(direction); } private: - virtual const char* renderName() const { return "RenderTextControl"; } - virtual bool isTextControl() const { return true; } - virtual bool supportsPartialLayout() const OVERRIDE { return false; } - virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE; - virtual void computePreferredLogicalWidths() OVERRIDE; - virtual void removeLeftoverAnonymousBlock(RenderBlock*) { } - virtual bool avoidsFloats() const { return true; } - virtual bool canHaveGeneratedChildren() const OVERRIDE { return false; } + virtual const char* renderName() const OVERRIDE { return "RenderTextControl"; } + virtual bool isTextControl() const OVERRIDE FINAL { return true; } + virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE FINAL; + virtual void computePreferredLogicalWidths() OVERRIDE FINAL; + virtual void removeLeftoverAnonymousBlock(RenderBlock*) OVERRIDE FINAL { } + virtual bool avoidsFloats() const OVERRIDE FINAL { return true; } + virtual bool canHaveGeneratedChildren() const OVERRIDE FINAL { return false; } virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0) OVERRIDE FINAL; - virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) OVERRIDE; + virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) OVERRIDE FINAL; - virtual bool canBeProgramaticallyScrolled() const { return true; } + virtual bool canBeProgramaticallyScrolled() const OVERRIDE FINAL { return true; } }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderTextControl, isTextControl()); @@ -104,7 +104,6 @@ public: } virtual int firstLineBoxBaseline() const OVERRIDE { return RenderBlock::firstLineBoxBaseline(); } virtual int inlineBlockBaseline(LineDirectionMode direction) const OVERRIDE { return lastLineBoxBaseline(direction); } - virtual bool supportsPartialLayout() const OVERRIDE { return false; } }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTextControlMultiLine.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderTextControlMultiLine.cpp index 01fa15a7d4d..eef715fa748 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTextControlMultiLine.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTextControlMultiLine.cpp @@ -35,8 +35,6 @@ RenderTextControlMultiLine::RenderTextControlMultiLine(HTMLTextAreaElement* elem RenderTextControlMultiLine::~RenderTextControlMultiLine() { - if (node() && node()->inDocument()) - toHTMLTextAreaElement(node())->rendererWillBeDestroyed(); } bool RenderTextControlMultiLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) @@ -44,8 +42,8 @@ bool RenderTextControlMultiLine::nodeAtPoint(const HitTestRequest& request, HitT if (!RenderTextControl::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction)) return false; - if (result.innerNode() == node() || result.innerNode() == innerTextElement()) - hitInnerTextElement(result, locationInContainer.point(), accumulatedOffset); + if (result.innerNode() == node() || result.innerNode() == innerEditorElement()) + hitInnerEditorElement(result, locationInContainer.point(), accumulatedOffset); return true; } @@ -77,11 +75,11 @@ int RenderTextControlMultiLine::baselinePosition(FontBaseline baselineType, bool return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode); } -PassRefPtr<RenderStyle> RenderTextControlMultiLine::createInnerTextStyle(const RenderStyle* startStyle) const +PassRefPtr<RenderStyle> RenderTextControlMultiLine::createInnerEditorStyle(const RenderStyle* startStyle) const { RefPtr<RenderStyle> textBlockStyle = RenderStyle::create(); textBlockStyle->inheritFrom(startStyle); - adjustInnerTextStyle(textBlockStyle.get()); + adjustInnerEditorStyle(textBlockStyle.get()); textBlockStyle->setDisplay(BLOCK); textBlockStyle->setUnique(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTextControlMultiLine.h b/chromium/third_party/WebKit/Source/core/rendering/RenderTextControlMultiLine.h index 3371c2602b0..73132f5372d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTextControlMultiLine.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTextControlMultiLine.h @@ -34,19 +34,19 @@ public: virtual ~RenderTextControlMultiLine(); private: - virtual bool isTextArea() const { return true; } + virtual bool isTextArea() const OVERRIDE { return true; } virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; - virtual float getAvgCharWidth(AtomicString family); - virtual LayoutUnit preferredContentLogicalWidth(float charWidth) const; + virtual float getAvgCharWidth(AtomicString family) OVERRIDE; + virtual LayoutUnit preferredContentLogicalWidth(float charWidth) const OVERRIDE; virtual LayoutUnit computeControlLogicalHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const OVERRIDE; // We override the two baseline functions because we want our baseline to be the bottom of our margin box. virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const OVERRIDE; virtual int inlineBlockBaseline(LineDirectionMode) const OVERRIDE { return -1; } - virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const; - virtual RenderObject* layoutSpecialExcludedChild(bool relayoutChildren, SubtreeLayoutScope&); + virtual PassRefPtr<RenderStyle> createInnerEditorStyle(const RenderStyle* startStyle) const OVERRIDE; + virtual RenderObject* layoutSpecialExcludedChild(bool relayoutChildren, SubtreeLayoutScope&) OVERRIDE; }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderTextControlMultiLine, isTextArea()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTextControlSingleLine.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderTextControlSingleLine.cpp index 04ecfea2fc8..b896d6c9c0b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTextControlSingleLine.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTextControlSingleLine.cpp @@ -24,13 +24,12 @@ #include "config.h" #include "core/rendering/RenderTextControlSingleLine.h" -#include "CSSValueKeywords.h" +#include "core/CSSValueKeywords.h" #include "core/dom/shadow/ShadowRoot.h" #include "core/editing/FrameSelection.h" +#include "core/frame/LocalFrame.h" #include "core/html/shadow/ShadowElementNames.h" -#include "core/frame/Frame.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderTheme.h" #include "platform/PlatformKeyboardEvent.h" @@ -45,9 +44,8 @@ using namespace HTMLNames; RenderTextControlSingleLine::RenderTextControlSingleLine(HTMLInputElement* element) : RenderTextControl(element) , m_shouldDrawCapsLockIndicator(false) - , m_desiredInnerTextLogicalHeight(-1) + , m_desiredInnerEditorLogicalHeight(-1) { - ASSERT(element->hasTagName(inputTag)); } RenderTextControlSingleLine::~RenderTextControlSingleLine() @@ -95,8 +93,7 @@ LayoutUnit RenderTextControlSingleLine::computeLogicalHeightLimit() const void RenderTextControlSingleLine::layout() { - LayoutRectRecorder recorder(*this); - SubtreeLayoutScope layoutScope(this); + SubtreeLayoutScope layoutScope(*this); // FIXME: We should remove the height-related hacks in layout() and // styleDidChange(). We need them because @@ -109,13 +106,16 @@ void RenderTextControlSingleLine::layout() // and type=search if the text height is taller than the contentHeight() // because of compability. - RenderBox* innerTextRenderer = innerTextElement()->renderBox(); + RenderBox* innerEditorRenderer = innerEditorElement()->renderBox(); RenderBox* viewPortRenderer = editingViewPortElement() ? editingViewPortElement()->renderBox() : 0; // To ensure consistency between layouts, we need to reset any conditionally overriden height. - if (innerTextRenderer && !innerTextRenderer->style()->logicalHeight().isAuto()) { - innerTextRenderer->style()->setLogicalHeight(Length(Auto)); - layoutScope.setNeedsLayout(innerTextRenderer); + if (innerEditorRenderer && !innerEditorRenderer->style()->logicalHeight().isAuto()) { + innerEditorRenderer->style()->setLogicalHeight(Length(Auto)); + layoutScope.setNeedsLayout(innerEditorRenderer); + HTMLElement* placeholderElement = inputElement()->placeholderElement(); + if (RenderBox* placeholderBox = placeholderElement ? placeholderElement->renderBox() : 0) + layoutScope.setNeedsLayout(placeholderBox); } if (viewPortRenderer && !viewPortRenderer->style()->logicalHeight().isAuto()) { viewPortRenderer->style()->setLogicalHeight(Length(Auto)); @@ -130,14 +130,14 @@ void RenderTextControlSingleLine::layout() // Set the text block height LayoutUnit desiredLogicalHeight = textBlockLogicalHeight(); LayoutUnit logicalHeightLimit = computeLogicalHeightLimit(); - if (innerTextRenderer && innerTextRenderer->logicalHeight() > logicalHeightLimit) { - if (desiredLogicalHeight != innerTextRenderer->logicalHeight()) + if (innerEditorRenderer && innerEditorRenderer->logicalHeight() > logicalHeightLimit) { + if (desiredLogicalHeight != innerEditorRenderer->logicalHeight()) layoutScope.setNeedsLayout(this); - m_desiredInnerTextLogicalHeight = desiredLogicalHeight; + m_desiredInnerEditorLogicalHeight = desiredLogicalHeight; - innerTextRenderer->style()->setLogicalHeight(Length(desiredLogicalHeight, Fixed)); - layoutScope.setNeedsLayout(innerTextRenderer); + innerEditorRenderer->style()->setLogicalHeight(Length(desiredLogicalHeight, Fixed)); + layoutScope.setNeedsLayout(innerEditorRenderer); if (viewPortRenderer) { viewPortRenderer->style()->setLogicalHeight(Length(desiredLogicalHeight, Fixed)); layoutScope.setNeedsLayout(viewPortRenderer); @@ -162,45 +162,36 @@ void RenderTextControlSingleLine::layout() RenderBlockFlow::layoutBlock(true); // Center the child block in the block progression direction (vertical centering for horizontal text fields). - if (!container && innerTextRenderer && innerTextRenderer->height() != contentLogicalHeight()) { - LayoutUnit logicalHeightDiff = innerTextRenderer->logicalHeight() - contentLogicalHeight(); - innerTextRenderer->setLogicalTop(innerTextRenderer->logicalTop() - (logicalHeightDiff / 2 + layoutMod(logicalHeightDiff, 2))); + if (!container && innerEditorRenderer && innerEditorRenderer->height() != contentLogicalHeight()) { + LayoutUnit logicalHeightDiff = innerEditorRenderer->logicalHeight() - contentLogicalHeight(); + innerEditorRenderer->setLogicalTop(innerEditorRenderer->logicalTop() - (logicalHeightDiff / 2 + layoutMod(logicalHeightDiff, 2))); } else centerContainerIfNeeded(containerRenderer); - // Ignores the paddings for the inner spin button. - if (RenderBox* innerSpinBox = innerSpinButtonElement() ? innerSpinButtonElement()->renderBox() : 0) { - RenderBox* parentBox = innerSpinBox->parentBox(); - if (containerRenderer && !containerRenderer->style()->isLeftToRightDirection()) - innerSpinBox->setLogicalLocation(LayoutPoint(-paddingLogicalLeft(), -paddingBefore())); - else - innerSpinBox->setLogicalLocation(LayoutPoint(parentBox->logicalWidth() - innerSpinBox->logicalWidth() + paddingLogicalRight(), -paddingBefore())); - innerSpinBox->setLogicalHeight(logicalHeight() - borderBefore() - borderAfter()); - } - HTMLElement* placeholderElement = inputElement()->placeholderElement(); if (RenderBox* placeholderBox = placeholderElement ? placeholderElement->renderBox() : 0) { - LayoutSize innerTextSize; - if (innerTextRenderer) - innerTextSize = innerTextRenderer->size(); - placeholderBox->style()->setWidth(Length(innerTextSize.width() - placeholderBox->borderAndPaddingWidth(), Fixed)); - placeholderBox->style()->setHeight(Length(innerTextSize.height() - placeholderBox->borderAndPaddingHeight(), Fixed)); + LayoutSize innerEditorSize; + + if (innerEditorRenderer) + innerEditorSize = innerEditorRenderer->size(); + placeholderBox->style()->setWidth(Length(innerEditorSize.width() - placeholderBox->borderAndPaddingWidth(), Fixed)); + placeholderBox->style()->setHeight(Length(innerEditorSize.height() - placeholderBox->borderAndPaddingHeight(), Fixed)); bool neededLayout = placeholderBox->needsLayout(); bool placeholderBoxHadLayout = placeholderBox->everHadLayout(); placeholderBox->layoutIfNeeded(); LayoutPoint textOffset; - if (innerTextRenderer) - textOffset = innerTextRenderer->location(); + if (innerEditorRenderer) + textOffset = innerEditorRenderer->location(); if (editingViewPortElement() && editingViewPortElement()->renderBox()) textOffset += toLayoutSize(editingViewPortElement()->renderBox()->location()); if (containerRenderer) textOffset += toLayoutSize(containerRenderer->location()); placeholderBox->setLocation(textOffset); - if (!placeholderBoxHadLayout && placeholderBox->checkForRepaintDuringLayout()) { + if (!placeholderBoxHadLayout && placeholderBox->checkForPaintInvalidationDuringLayout()) { // This assumes a shadow tree without floats. If floats are added, the - // logic should be shared with RenderBlock::layoutBlockChild. - placeholderBox->repaint(); + // logic should be shared with RenderBlockFlow::layoutBlockChild. + placeholderBox->paintInvalidationForWholeRenderer(); } // The placeholder gets layout last, after the parent text control and its other children, // so in order to get the correct overflow from the placeholder we need to recompute it now. @@ -219,7 +210,7 @@ bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, Hit // - we hit the <input> element (e.g. we're over the border or padding), or // - we hit regions not in any decoration buttons. Element* container = containerElement(); - if (result.innerNode()->isDescendantOf(innerTextElement()) || result.innerNode() == node() || (container && container == result.innerNode())) { + if (result.innerNode()->isDescendantOf(innerEditorElement()) || result.innerNode() == node() || (container && container == result.innerNode())) { LayoutPoint pointInParent = locationInContainer.point(); if (container && editingViewPortElement()) { if (editingViewPortElement()->renderBox()) @@ -227,14 +218,14 @@ bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, Hit if (container->renderBox()) pointInParent -= toLayoutSize(container->renderBox()->location()); } - hitInnerTextElement(result, pointInParent, accumulatedOffset); + hitInnerEditorElement(result, pointInParent, accumulatedOffset); } return true; } void RenderTextControlSingleLine::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - m_desiredInnerTextLogicalHeight = -1; + m_desiredInnerEditorLogicalHeight = -1; RenderTextControl::styleDidChange(diff, oldStyle); // We may have set the width and the height in the old style in layout(). @@ -249,9 +240,9 @@ void RenderTextControlSingleLine::styleDidChange(StyleDifference diff, const Ren containerRenderer->style()->setHeight(Length()); containerRenderer->style()->setWidth(Length()); } - RenderObject* innerTextRenderer = innerTextElement()->renderer(); - if (innerTextRenderer && diff == StyleDifferenceLayout) - innerTextRenderer->setNeedsLayout(); + RenderObject* innerEditorRenderer = innerEditorElement()->renderer(); + if (innerEditorRenderer && diff.needsFullLayout()) + innerEditorRenderer->setNeedsLayoutAndFullPaintInvalidation(); if (HTMLElement* placeholder = inputElement()->placeholderElement()) placeholder->setInlineStyleProperty(CSSPropertyTextOverflow, textShouldBeTruncated() ? CSSValueEllipsis : CSSValueClip); setHasOverflowClip(false); @@ -269,12 +260,12 @@ void RenderTextControlSingleLine::capsLockStateMayHaveChanged() // 4) The caps lock is on bool shouldDrawCapsLockIndicator = false; - if (Frame* frame = document().frame()) + if (LocalFrame* frame = document().frame()) shouldDrawCapsLockIndicator = inputElement()->isPasswordField() && frame->selection().isFocusedAndActive() && document().focusedElement() == node() && PlatformKeyboardEvent::currentCapsLockState(); if (shouldDrawCapsLockIndicator != m_shouldDrawCapsLockIndicator) { m_shouldDrawCapsLockIndicator = shouldDrawCapsLockIndicator; - repaint(); + paintInvalidationForWholeRenderer(); } } @@ -316,7 +307,7 @@ LayoutUnit RenderTextControlSingleLine::preferredContentLogicalWidth(float charW LayoutUnit result = LayoutUnit::fromFloatCeil(charWidth * factor); float maxCharWidth = 0.f; - AtomicString family = style()->font().family().family(); + AtomicString family = style()->font().fontDescription().family().family(); // Since Lucida Grande is the default font, we want this to match the width // of MS Shell Dlg, the default font for textareas in Firefox, Safari Win and // IE for some encodings (in IE, the default font is encoding specific). @@ -348,16 +339,11 @@ LayoutUnit RenderTextControlSingleLine::computeControlLogicalHeight(LayoutUnit l return lineHeight + nonContentHeight; } -void RenderTextControlSingleLine::updateFromElement() -{ - RenderTextControl::updateFromElement(); -} - -PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const RenderStyle* startStyle) const +PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerEditorStyle(const RenderStyle* startStyle) const { RefPtr<RenderStyle> textBlockStyle = RenderStyle::create(); textBlockStyle->inheritFrom(startStyle); - adjustInnerTextStyle(textBlockStyle.get()); + adjustInnerEditorStyle(textBlockStyle.get()); textBlockStyle->setWhiteSpace(PRE); textBlockStyle->setOverflowWrap(NormalOverflowWrap); @@ -365,8 +351,8 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const textBlockStyle->setOverflowY(OHIDDEN); textBlockStyle->setTextOverflow(textShouldBeTruncated() ? TextOverflowEllipsis : TextOverflowClip); - if (m_desiredInnerTextLogicalHeight >= 0) - textBlockStyle->setLogicalHeight(Length(m_desiredInnerTextLogicalHeight, Fixed)); + if (m_desiredInnerEditorLogicalHeight >= 0) + textBlockStyle->setLogicalHeight(Length(m_desiredInnerEditorLogicalHeight, Fixed)); // Do not allow line-height to be smaller than our default. if (textBlockStyle->fontMetrics().lineSpacing() > lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes)) textBlockStyle->setLineHeight(RenderStyle::initialLineHeight()); @@ -374,6 +360,9 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const textBlockStyle->setDisplay(BLOCK); textBlockStyle->setUnique(); + if (inputElement()->shouldRevealPassword()) + textBlockStyle->setTextSecurity(TSNONE); + return textBlockStyle.release(); } @@ -384,51 +373,51 @@ bool RenderTextControlSingleLine::textShouldBeTruncated() const void RenderTextControlSingleLine::autoscroll(const IntPoint& position) { - RenderBox* renderer = innerTextElement()->renderBox(); + RenderBox* renderer = innerEditorElement()->renderBox(); if (!renderer) return; renderer->autoscroll(position); } -int RenderTextControlSingleLine::scrollWidth() const +LayoutUnit RenderTextControlSingleLine::scrollWidth() const { - if (innerTextElement()) - return innerTextElement()->scrollWidth(); - return RenderBlock::scrollWidth(); + if (innerEditorElement()) + return innerEditorElement()->scrollWidth(); + return RenderBlockFlow::scrollWidth(); } -int RenderTextControlSingleLine::scrollHeight() const +LayoutUnit RenderTextControlSingleLine::scrollHeight() const { - if (innerTextElement()) - return innerTextElement()->scrollHeight(); - return RenderBlock::scrollHeight(); + if (innerEditorElement()) + return innerEditorElement()->scrollHeight(); + return RenderBlockFlow::scrollHeight(); } -int RenderTextControlSingleLine::scrollLeft() const +LayoutUnit RenderTextControlSingleLine::scrollLeft() const { - if (innerTextElement()) - return innerTextElement()->scrollLeft(); - return RenderBlock::scrollLeft(); + if (innerEditorElement()) + return innerEditorElement()->scrollLeft(); + return RenderBlockFlow::scrollLeft(); } -int RenderTextControlSingleLine::scrollTop() const +LayoutUnit RenderTextControlSingleLine::scrollTop() const { - if (innerTextElement()) - return innerTextElement()->scrollTop(); - return RenderBlock::scrollTop(); + if (innerEditorElement()) + return innerEditorElement()->scrollTop(); + return RenderBlockFlow::scrollTop(); } -void RenderTextControlSingleLine::setScrollLeft(int newLeft) +void RenderTextControlSingleLine::setScrollLeft(LayoutUnit newLeft) { - if (innerTextElement()) - innerTextElement()->setScrollLeft(newLeft); + if (innerEditorElement()) + innerEditorElement()->setScrollLeft(newLeft); } -void RenderTextControlSingleLine::setScrollTop(int newTop) +void RenderTextControlSingleLine::setScrollTop(LayoutUnit newTop) { - if (innerTextElement()) - innerTextElement()->setScrollTop(newTop); + if (innerEditorElement()) + innerEditorElement()->setScrollTop(newTop); } HTMLInputElement* RenderTextControlSingleLine::inputElement() const diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTextControlSingleLine.h b/chromium/third_party/WebKit/Source/core/rendering/RenderTextControlSingleLine.h index 64a07cc74fc..60715c0deb9 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTextControlSingleLine.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTextControlSingleLine.h @@ -34,8 +34,8 @@ class RenderTextControlSingleLine : public RenderTextControl { public: RenderTextControlSingleLine(HTMLInputElement*); virtual ~RenderTextControlSingleLine(); - // FIXME: Move createInnerTextStyle() to TextControlInnerTextElement. - virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const; + // FIXME: Move createInnerEditorStyle() to TextControlInnerEditorElement. + virtual PassRefPtr<RenderStyle> createInnerEditorStyle(const RenderStyle* startStyle) const OVERRIDE FINAL; void capsLockStateMayHaveChanged(); @@ -45,41 +45,40 @@ protected: Element* containerElement() const; Element* editingViewPortElement() const; HTMLInputElement* inputElement() const; - virtual void updateFromElement() OVERRIDE; private: - virtual bool hasControlClip() const; - virtual LayoutRect controlClipRect(const LayoutPoint&) const; - virtual bool isTextField() const { return true; } + virtual bool hasControlClip() const OVERRIDE FINAL; + virtual LayoutRect controlClipRect(const LayoutPoint&) const OVERRIDE FINAL; + virtual bool isTextField() const OVERRIDE FINAL { return true; } - virtual void paint(PaintInfo&, const LayoutPoint&); - virtual void layout(); + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; + virtual void layout() OVERRIDE; - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE FINAL; - virtual void autoscroll(const IntPoint&); + virtual void autoscroll(const IntPoint&) OVERRIDE FINAL; // Subclassed to forward to our inner div. - virtual int scrollLeft() const; - virtual int scrollTop() const; - virtual int scrollWidth() const; - virtual int scrollHeight() const; - virtual void setScrollLeft(int); - virtual void setScrollTop(int); + virtual LayoutUnit scrollLeft() const OVERRIDE FINAL; + virtual LayoutUnit scrollTop() const OVERRIDE FINAL; + virtual LayoutUnit scrollWidth() const OVERRIDE FINAL; + virtual LayoutUnit scrollHeight() const OVERRIDE FINAL; + virtual void setScrollLeft(LayoutUnit) OVERRIDE FINAL; + virtual void setScrollTop(LayoutUnit) OVERRIDE FINAL; int textBlockWidth() const; - virtual float getAvgCharWidth(AtomicString family); - virtual LayoutUnit preferredContentLogicalWidth(float charWidth) const; + virtual float getAvgCharWidth(AtomicString family) OVERRIDE FINAL; + virtual LayoutUnit preferredContentLogicalWidth(float charWidth) const OVERRIDE FINAL; virtual LayoutUnit computeControlLogicalHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const OVERRIDE; - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE FINAL; bool textShouldBeTruncated() const; HTMLElement* innerSpinButtonElement() const; bool m_shouldDrawCapsLockIndicator; - LayoutUnit m_desiredInnerTextLogicalHeight; + LayoutUnit m_desiredInnerEditorLogicalHeight; }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderTextControlSingleLine, isTextField()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTextFragment.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderTextFragment.cpp index 759eb9dd368..f2eb3ff2262 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTextFragment.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTextFragment.cpp @@ -30,7 +30,7 @@ namespace WebCore { RenderTextFragment::RenderTextFragment(Node* node, StringImpl* str, int startOffset, int length) - : RenderText(node, str ? str->substring(startOffset, length) : PassRefPtr<StringImpl>(0)) + : RenderText(node, str ? str->substring(startOffset, length) : PassRefPtr<StringImpl>(nullptr)) , m_start(startOffset) , m_end(length) , m_firstLetter(0) @@ -64,7 +64,7 @@ PassRefPtr<StringImpl> RenderTextFragment::originalText() const Node* e = node(); RefPtr<StringImpl> result = ((e && e->isTextNode()) ? toText(e)->dataImpl() : contentString()); if (!result) - return 0; + return nullptr; return result->substring(start(), end()); } @@ -92,6 +92,10 @@ void RenderTextFragment::setText(PassRefPtr<StringImpl> text, bool force) m_start = 0; m_end = textLength(); if (m_firstLetter) { + // FIXME: We should not modify the structure of the render tree during + // layout. crbug.com/370458 + DeprecatedDisableModifyRenderTreeStructureAsserts disabler; + ASSERT(!m_contentString); m_firstLetter->destroy(); m_firstLetter = 0; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTextFragment.h b/chromium/third_party/WebKit/Source/core/rendering/RenderTextFragment.h index 44bbfe81f6d..de9858c4862 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTextFragment.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTextFragment.h @@ -37,7 +37,7 @@ public: RenderTextFragment(Node*, StringImpl*); virtual ~RenderTextFragment(); - virtual bool isTextFragment() const { return true; } + virtual bool isTextFragment() const OVERRIDE { return true; } virtual bool canBeSelectionLeaf() const OVERRIDE { return node() && node()->rendererIsEditable(); } @@ -45,31 +45,31 @@ public: unsigned end() const { return m_end; } virtual unsigned textStartOffset() const OVERRIDE { return start(); } - RenderObject* firstLetter() const { return m_firstLetter; } - void setFirstLetter(RenderObject* firstLetter) { m_firstLetter = firstLetter; } + RenderBoxModelObject* firstLetter() const { return m_firstLetter; } + void setFirstLetter(RenderBoxModelObject* firstLetter) { m_firstLetter = firstLetter; } RenderText* firstRenderTextInFirstLetter() const; StringImpl* contentString() const { return m_contentString.get(); } - virtual PassRefPtr<StringImpl> originalText() const; + virtual PassRefPtr<StringImpl> originalText() const OVERRIDE; virtual void setText(PassRefPtr<StringImpl>, bool force = false) OVERRIDE; virtual void transformText() OVERRIDE; protected: - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; private: - virtual void willBeDestroyed(); + virtual void willBeDestroyed() OVERRIDE; - virtual UChar previousCharacter() const; + virtual UChar previousCharacter() const OVERRIDE; RenderBlock* blockForAccompanyingFirstLetter() const; virtual void updateHitTestResult(HitTestResult&, const LayoutPoint&) OVERRIDE; unsigned m_start; unsigned m_end; RefPtr<StringImpl> m_contentString; - RenderObject* m_firstLetter; + RenderBoxModelObject* m_firstLetter; }; DEFINE_TYPE_CASTS(RenderTextFragment, RenderObject, object, toRenderText(object)->isTextFragment(), toRenderText(object).isTextFragment()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTheme.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderTheme.cpp index 90c56f77dbd..3c0e2c6fe12 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTheme.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTheme.cpp @@ -22,16 +22,17 @@ #include "config.h" #include "core/rendering/RenderTheme.h" -#include "CSSValueKeywords.h" -#include "HTMLNames.h" -#include "InputTypeNames.h" -#include "RuntimeEnabledFeatures.h" +#include "core/CSSValueKeywords.h" +#include "core/HTMLNames.h" +#include "core/InputTypeNames.h" #include "core/dom/Document.h" #include "core/dom/shadow/ElementShadow.h" #include "core/editing/FrameSelection.h" #include "core/fileapi/FileList.h" +#include "core/frame/LocalFrame.h" #include "core/html/HTMLCollection.h" #include "core/html/HTMLDataListElement.h" +#include "core/html/HTMLFormControlElement.h" #include "core/html/HTMLInputElement.h" #include "core/html/HTMLMeterElement.h" #include "core/html/HTMLOptionElement.h" @@ -41,7 +42,6 @@ #include "core/html/shadow/SpinButtonElement.h" #include "core/html/shadow/TextControlInnerElements.h" #include "core/page/FocusController.h" -#include "core/frame/Frame.h" #include "core/page/Page.h" #include "core/frame/Settings.h" #include "core/rendering/PaintInfo.h" @@ -50,6 +50,7 @@ #include "core/rendering/style/RenderStyle.h" #include "platform/FileMetadata.h" #include "platform/FloatConversion.h" +#include "platform/RuntimeEnabledFeatures.h" #include "platform/fonts/FontSelector.h" #include "platform/graphics/GraphicsContextStateSaver.h" #include "platform/text/PlatformLocale.h" @@ -59,22 +60,12 @@ #include "public/platform/WebRect.h" #include "wtf/text/StringBuilder.h" -#if ENABLE(INPUT_SPEECH) -#include "core/rendering/RenderInputSpeech.h" -#endif - // The methods in this file are shared by all themes on every platform. namespace WebCore { using namespace HTMLNames; -static Color& customFocusRingColor() -{ - DEFINE_STATIC_LOCAL(Color, color, ()); - return color; -} - static blink::WebFallbackThemeEngine::State getWebFallbackThemeState(const RenderTheme* theme, const RenderObject* o) { if (!theme->isEnabled(o)) @@ -88,13 +79,14 @@ static blink::WebFallbackThemeEngine::State getWebFallbackThemeState(const Rende } RenderTheme::RenderTheme() + : m_hasCustomFocusRingColor(false) #if USE(NEW_THEME) - : m_platformTheme(platformTheme()) + , m_platformTheme(platformTheme()) #endif { } -void RenderTheme::adjustStyle(RenderStyle* style, Element* e, const CachedUAStyle& uaStyle) +void RenderTheme::adjustStyle(RenderStyle* style, Element* e, const CachedUAStyle* uaStyle) { // Force inline and table display styles to be inline-block (except for table- which is block) ControlPart part = style->appearance(); @@ -106,7 +98,7 @@ void RenderTheme::adjustStyle(RenderStyle* style, Element* e, const CachedUAStyl else if (style->display() == LIST_ITEM || style->display() == TABLE) style->setDisplay(BLOCK); - if (uaStyle.hasAppearance && isControlStyled(style, uaStyle)) { + if (uaStyle && uaStyle->hasAppearance && isControlStyled(style, uaStyle)) { if (part == MenulistPart) { style->setAppearance(MenulistButtonPart); part = MenulistButtonPart; @@ -193,7 +185,7 @@ void RenderTheme::adjustStyle(RenderStyle* style, Element* e, const CachedUAStyl // Now update our font. if (style->setFontDescription(controlFont)) - style->font().update(0); + style->font().update(nullptr); } } default: @@ -230,10 +222,6 @@ void RenderTheme::adjustStyle(RenderStyle* style, Element* e, const CachedUAStyl return adjustSearchFieldDecorationStyle(style, e); case SearchFieldResultsDecorationPart: return adjustSearchFieldResultsDecorationStyle(style, e); -#if ENABLE(INPUT_SPEECH) - case InputSpeechButtonPart: - return adjustInputFieldSpeechButtonStyle(style, e); -#endif default: break; } @@ -246,12 +234,9 @@ bool RenderTheme::paint(RenderObject* o, const PaintInfo& paintInfo, const IntRe // for that control. if (paintInfo.context->updatingControlTints()) { if (controlSupportsTints(o)) - o->repaint(); + o->paintInvalidationForWholeRenderer(); return false; } - if (paintInfo.context->paintingDisabled()) - return false; - ControlPart part = o->style()->appearance(); if (shouldUseFallbackTheme(o->style())) @@ -311,22 +296,12 @@ bool RenderTheme::paint(RenderObject* o, const PaintInfo& paintInfo, const IntRe return paintMediaOverlayPlayButton(o, paintInfo, r); case MediaMuteButtonPart: return paintMediaMuteButton(o, paintInfo, r); - case MediaSeekBackButtonPart: - return paintMediaSeekBackButton(o, paintInfo, r); - case MediaSeekForwardButtonPart: - return paintMediaSeekForwardButton(o, paintInfo, r); - case MediaRewindButtonPart: - return paintMediaRewindButton(o, paintInfo, r); - case MediaReturnToRealtimeButtonPart: - return paintMediaReturnToRealtimeButton(o, paintInfo, r); case MediaToggleClosedCaptionsButtonPart: return paintMediaToggleClosedCaptionsButton(o, paintInfo, r); case MediaSliderPart: return paintMediaSliderTrack(o, paintInfo, r); case MediaSliderThumbPart: return paintMediaSliderThumb(o, paintInfo, r); - case MediaVolumeSliderMuteButtonPart: - return paintMediaMuteButton(o, paintInfo, r); case MediaVolumeSliderContainerPart: return paintMediaVolumeSliderContainer(o, paintInfo, r); case MediaVolumeSliderPart: @@ -356,10 +331,6 @@ bool RenderTheme::paint(RenderObject* o, const PaintInfo& paintInfo, const IntRe return paintSearchFieldDecoration(o, paintInfo, r); case SearchFieldResultsDecorationPart: return paintSearchFieldResultsDecoration(o, paintInfo, r); -#if ENABLE(INPUT_SPEECH) - case InputSpeechButtonPart: - return paintInputFieldSpeechButton(o, paintInfo, r); -#endif default: break; } @@ -369,9 +340,6 @@ bool RenderTheme::paint(RenderObject* o, const PaintInfo& paintInfo, const IntRe bool RenderTheme::paintBorderOnly(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { - if (paintInfo.context->paintingDisabled()) - return false; - // Call the appropriate paint method based off the appearance value. switch (o->style()->appearance()) { case TextFieldPart: @@ -401,9 +369,6 @@ bool RenderTheme::paintBorderOnly(RenderObject* o, const PaintInfo& paintInfo, c case SearchFieldCancelButtonPart: case SearchFieldDecorationPart: case SearchFieldResultsDecorationPart: -#if ENABLE(INPUT_SPEECH) - case InputSpeechButtonPart: -#endif default: break; } @@ -413,9 +378,6 @@ bool RenderTheme::paintBorderOnly(RenderObject* o, const PaintInfo& paintInfo, c bool RenderTheme::paintDecorations(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { - if (paintInfo.context->paintingDisabled()) - return false; - // Call the appropriate paint method based off the appearance value. switch (o->style()->appearance()) { case MenulistButtonPart: @@ -443,9 +405,6 @@ bool RenderTheme::paintDecorations(RenderObject* o, const PaintInfo& paintInfo, case SearchFieldCancelButtonPart: case SearchFieldDecorationPart: case SearchFieldResultsDecorationPart: -#if ENABLE(INPUT_SPEECH) - case InputSpeechButtonPart: -#endif default: break; } @@ -455,19 +414,7 @@ bool RenderTheme::paintDecorations(RenderObject* o, const PaintInfo& paintInfo, String RenderTheme::extraDefaultStyleSheet() { - if (!RuntimeEnabledFeatures::dataListElementEnabled() && !RuntimeEnabledFeatures::dialogElementEnabled()) - return String(); StringBuilder runtimeCSS; - - if (RuntimeEnabledFeatures::dataListElementEnabled()) { - runtimeCSS.appendLiteral("datalist {display: none ;}"); - - if (RuntimeEnabledFeatures::inputTypeColorEnabled()) { - runtimeCSS.appendLiteral("input[type=\"color\"][list] { -webkit-appearance: menulist; width: 88px; height: 23px;}"); - runtimeCSS.appendLiteral("input[type=\"color\"][list]::-webkit-color-swatch-wrapper { padding-left: 8px; padding-right: 24px;}"); - runtimeCSS.appendLiteral("input[type=\"color\"][list]::-webkit-color-swatch { border-color: #000000;}"); - } - } if (RuntimeEnabledFeatures::dialogElementEnabled()) { runtimeCSS.appendLiteral("dialog:not([open]) { display: none; }"); runtimeCSS.appendLiteral("dialog { position: absolute; left: 0; right: 0; width: -webkit-fit-content; height: -webkit-fit-content; margin: auto; border: solid; padding: 1em; background: white; color: black;}"); @@ -502,58 +449,42 @@ String RenderTheme::formatMediaControlsCurrentTime(float currentTime, float /*du Color RenderTheme::activeSelectionBackgroundColor() const { - if (!m_activeSelectionBackgroundColor.isValid()) - m_activeSelectionBackgroundColor = platformActiveSelectionBackgroundColor().blendWithWhite(); - return m_activeSelectionBackgroundColor; + return platformActiveSelectionBackgroundColor().blendWithWhite(); } Color RenderTheme::inactiveSelectionBackgroundColor() const { - if (!m_inactiveSelectionBackgroundColor.isValid()) - m_inactiveSelectionBackgroundColor = platformInactiveSelectionBackgroundColor().blendWithWhite(); - return m_inactiveSelectionBackgroundColor; + return platformInactiveSelectionBackgroundColor().blendWithWhite(); } Color RenderTheme::activeSelectionForegroundColor() const { - if (!m_activeSelectionForegroundColor.isValid() && supportsSelectionForegroundColors()) - m_activeSelectionForegroundColor = platformActiveSelectionForegroundColor(); - return m_activeSelectionForegroundColor; + return platformActiveSelectionForegroundColor(); } Color RenderTheme::inactiveSelectionForegroundColor() const { - if (!m_inactiveSelectionForegroundColor.isValid() && supportsSelectionForegroundColors()) - m_inactiveSelectionForegroundColor = platformInactiveSelectionForegroundColor(); - return m_inactiveSelectionForegroundColor; + return platformInactiveSelectionForegroundColor(); } Color RenderTheme::activeListBoxSelectionBackgroundColor() const { - if (!m_activeListBoxSelectionBackgroundColor.isValid()) - m_activeListBoxSelectionBackgroundColor = platformActiveListBoxSelectionBackgroundColor(); - return m_activeListBoxSelectionBackgroundColor; + return platformActiveListBoxSelectionBackgroundColor(); } Color RenderTheme::inactiveListBoxSelectionBackgroundColor() const { - if (!m_inactiveListBoxSelectionBackgroundColor.isValid()) - m_inactiveListBoxSelectionBackgroundColor = platformInactiveListBoxSelectionBackgroundColor(); - return m_inactiveListBoxSelectionBackgroundColor; + return platformInactiveListBoxSelectionBackgroundColor(); } Color RenderTheme::activeListBoxSelectionForegroundColor() const { - if (!m_activeListBoxSelectionForegroundColor.isValid() && supportsListBoxSelectionForegroundColors()) - m_activeListBoxSelectionForegroundColor = platformActiveListBoxSelectionForegroundColor(); - return m_activeListBoxSelectionForegroundColor; + return platformActiveListBoxSelectionForegroundColor(); } Color RenderTheme::inactiveListBoxSelectionForegroundColor() const { - if (!m_inactiveListBoxSelectionForegroundColor.isValid() && supportsListBoxSelectionForegroundColors()) - m_inactiveListBoxSelectionForegroundColor = platformInactiveListBoxSelectionForegroundColor(); - return m_inactiveListBoxSelectionForegroundColor; + return platformInactiveListBoxSelectionForegroundColor(); } Color RenderTheme::platformActiveSelectionBackgroundColor() const @@ -637,8 +568,10 @@ static bool isBackgroundOrBorderStyled(const RenderStyle& style, const CachedUAS || style.visitedDependentColor(CSSPropertyBackgroundColor) != uaStyle.backgroundColor; } -bool RenderTheme::isControlStyled(const RenderStyle* style, const CachedUAStyle& uaStyle) const +bool RenderTheme::isControlStyled(const RenderStyle* style, const CachedUAStyle* uaStyle) const { + ASSERT(uaStyle); + switch (style->appearance()) { case PushButtonPart: case SquareButtonPart: @@ -649,14 +582,14 @@ bool RenderTheme::isControlStyled(const RenderStyle* style, const CachedUAStyle& case ContinuousCapacityLevelIndicatorPart: case DiscreteCapacityLevelIndicatorPart: case RatingLevelIndicatorPart: - return isBackgroundOrBorderStyled(*style, uaStyle); + return isBackgroundOrBorderStyled(*style, *uaStyle); case ListboxPart: case MenulistPart: case SearchFieldPart: case TextAreaPart: case TextFieldPart: - return isBackgroundOrBorderStyled(*style, uaStyle) || style->boxShadow(); + return isBackgroundOrBorderStyled(*style, *uaStyle) || style->boxShadow(); case SliderHorizontalPart: case SliderVerticalPart: @@ -698,15 +631,15 @@ bool RenderTheme::supportsFocusRing(const RenderStyle* style) const bool RenderTheme::stateChanged(RenderObject* o, ControlState state) const { // Default implementation assumes the controls don't respond to changes in :hover state - if (state == HoverState && !supportsHover(o->style())) + if (state == HoverControlState && !supportsHover(o->style())) return false; // Assume pressed state is only responded to if the control is enabled. - if (state == PressedState && !isEnabled(o)) + if (state == PressedControlState && !isEnabled(o)) return false; // Repaint the control. - o->repaint(); + o->paintInvalidationForWholeRenderer(); return true; } @@ -714,27 +647,27 @@ ControlStates RenderTheme::controlStatesForRenderer(const RenderObject* o) const { ControlStates result = 0; if (isHovered(o)) { - result |= HoverState; + result |= HoverControlState; if (isSpinUpButtonPartHovered(o)) - result |= SpinUpState; + result |= SpinUpControlState; } if (isPressed(o)) { - result |= PressedState; + result |= PressedControlState; if (isSpinUpButtonPartPressed(o)) - result |= SpinUpState; + result |= SpinUpControlState; } if (isFocused(o) && o->style()->outlineStyleIsAuto()) - result |= FocusState; + result |= FocusControlState; if (isEnabled(o)) - result |= EnabledState; + result |= EnabledControlState; if (isChecked(o)) - result |= CheckedState; + result |= CheckedControlState; if (isReadOnlyControl(o)) - result |= ReadOnlyState; + result |= ReadOnlyControlState; if (!isActive(o)) - result |= WindowInactiveState; + result |= WindowInactiveControlState; if (isIndeterminate(o)) - result |= IndeterminateState; + result |= IndeterminateControlState; return result; } @@ -753,14 +686,14 @@ bool RenderTheme::isActive(const RenderObject* o) const bool RenderTheme::isChecked(const RenderObject* o) const { - if (!o->node() || !o->node()->hasTagName(inputTag)) + if (!isHTMLInputElement(o->node())) return false; return toHTMLInputElement(o->node())->shouldAppearChecked(); } bool RenderTheme::isIndeterminate(const RenderObject* o) const { - if (!o->node() || !o->node()->hasTagName(inputTag)) + if (!isHTMLInputElement(o->node())) return false; return toHTMLInputElement(o->node())->shouldAppearIndeterminate(); } @@ -781,8 +714,8 @@ bool RenderTheme::isFocused(const RenderObject* o) const node = node->focusDelegate(); Document& document = node->document(); - Frame* frame = document.frame(); - return node == document.focusedElement() && node->shouldHaveFocusAppearance() && frame && frame->selection().isFocusedAndActive(); + LocalFrame* frame = document.frame(); + return node == document.focusedElement() && node->focused() && node->shouldHaveFocusAppearance() && frame && frame->selection().isFocusedAndActive(); } bool RenderTheme::isPressed(const RenderObject* o) const @@ -805,9 +738,10 @@ bool RenderTheme::isSpinUpButtonPartPressed(const RenderObject* o) const bool RenderTheme::isReadOnlyControl(const RenderObject* o) const { Node* node = o->node(); - if (!node || !node->isElementNode()) + if (!node || !node->isElementNode() || !toElement(node)->isFormControlElement()) return false; - return toElement(node)->matchesReadOnlyPseudoClass(); + HTMLFormControlElement* element = toHTMLFormControlElement(node); + return element->isReadOnly(); } bool RenderTheme::isHovered(const RenderObject* o) const @@ -875,18 +809,6 @@ void RenderTheme::adjustMenuListStyle(RenderStyle*, Element*) const { } -#if ENABLE(INPUT_SPEECH) -void RenderTheme::adjustInputFieldSpeechButtonStyle(RenderStyle* style, Element* element) const -{ - RenderInputSpeech::adjustInputFieldSpeechButtonStyle(style, element); -} - -bool RenderTheme::paintInputFieldSpeechButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) -{ - return RenderInputSpeech::paintInputFieldSpeechButton(object, paintInfo, rect); -} -#endif - IntSize RenderTheme::meterSizeForBounds(const RenderMeter*, const IntRect& bounds) const { return bounds.size(); @@ -905,10 +827,13 @@ bool RenderTheme::paintMeter(RenderObject*, const PaintInfo&, const IntRect&) void RenderTheme::paintSliderTicks(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect) { Node* node = o->node(); - if (!node || !node->hasTagName(inputTag)) + if (!isHTMLInputElement(node)) return; HTMLInputElement* input = toHTMLInputElement(node); + if (!input->isRangeControl()) + return; + HTMLDataListElement* dataList = input->dataList(); if (!dataList) return; @@ -960,13 +885,13 @@ void RenderTheme::paintSliderTicks(RenderObject* o, const PaintInfo& paintInfo, tickRegionSideMargin = trackBounds.y() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0; tickRegionWidth = trackBounds.height() - thumbSize.width(); } - RefPtr<HTMLCollection> options = dataList->options(); + RefPtrWillBeRawPtr<HTMLCollection> options = dataList->options(); GraphicsContextStateSaver stateSaver(*paintInfo.context); paintInfo.context->setFillColor(o->resolveColor(CSSPropertyColor)); - for (unsigned i = 0; Node* node = options->item(i); i++) { - ASSERT(node->hasTagName(optionTag)); - HTMLOptionElement* optionElement = toHTMLOptionElement(node); - String value = optionElement->value(); + for (unsigned i = 0; Element* element = options->item(i); i++) { + ASSERT(isHTMLOptionElement(*element)); + HTMLOptionElement& optionElement = toHTMLOptionElement(*element); + String value = optionElement.value(); if (!input->isValidValue(value)) continue; double parsedValue = parseToDoubleForNumberType(input->sanitizeValue(value)); @@ -1027,16 +952,6 @@ void RenderTheme::adjustSearchFieldResultsDecorationStyle(RenderStyle*, Element* void RenderTheme::platformColorsDidChange() { - m_activeSelectionForegroundColor = Color(); - m_inactiveSelectionForegroundColor = Color(); - m_activeSelectionBackgroundColor = Color(); - m_inactiveSelectionBackgroundColor = Color(); - - m_activeListBoxSelectionForegroundColor = Color(); - m_inactiveListBoxSelectionForegroundColor = Color(); - m_activeListBoxSelectionBackgroundColor = Color(); - m_inactiveListBoxSelectionForegroundColor = Color(); - Page::scheduleForcedStyleRecalcForAllPages(); } @@ -1116,6 +1031,7 @@ Color RenderTheme::systemColor(CSSValueID cssValueId) const default: break; } + ASSERT_NOT_REACHED(); return Color(); } @@ -1136,12 +1052,13 @@ Color RenderTheme::tapHighlightColor() void RenderTheme::setCustomFocusRingColor(const Color& c) { - customFocusRingColor() = c; + m_customFocusRingColor = c; + m_hasCustomFocusRingColor = true; } -Color RenderTheme::focusRingColor() +Color RenderTheme::focusRingColor() const { - return customFocusRingColor().isValid() ? customFocusRingColor() : theme().platformFocusRingColor(); + return m_hasCustomFocusRingColor ? m_customFocusRingColor : theme().platformFocusRingColor(); } String RenderTheme::fileListNameForWidth(Locale& locale, const FileList* fileList, const Font& font, int width) const @@ -1167,20 +1084,6 @@ bool RenderTheme::shouldOpenPickerWithF4Key() const return false; } -bool RenderTheme::supportsDataListUI(const AtomicString& type) const -{ - return type == InputTypeNames::text || type == InputTypeNames::search || type == InputTypeNames::url - || type == InputTypeNames::tel || type == InputTypeNames::email || type == InputTypeNames::number - || type == InputTypeNames::color - || type == InputTypeNames::date - || type == InputTypeNames::datetime - || type == InputTypeNames::datetime_local - || type == InputTypeNames::month - || type == InputTypeNames::week - || type == InputTypeNames::time - || type == InputTypeNames::range; -} - #if ENABLE(INPUT_MULTIPLE_FIELDS_UI) bool RenderTheme::supportsCalendarPicker(const AtomicString& type) const { @@ -1235,6 +1138,8 @@ void RenderTheme::setSizeIfAuto(RenderStyle* style, const IntSize& size) bool RenderTheme::paintCheckboxUsingFallbackTheme(RenderObject* o, const PaintInfo& i, const IntRect& r) { + if (i.context->paintingDisabled()) + return false; blink::WebFallbackThemeEngine::ExtraParams extraParams; blink::WebCanvas* canvas = i.context->canvas(); extraParams.button.checked = isChecked(o); @@ -1247,7 +1152,7 @@ bool RenderTheme::paintCheckboxUsingFallbackTheme(RenderObject* o, const PaintIn unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); i.context->translate(unzoomedRect.x(), unzoomedRect.y()); - i.context->scale(FloatSize(zoomLevel, zoomLevel)); + i.context->scale(zoomLevel, zoomLevel); i.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); } @@ -1277,6 +1182,8 @@ void RenderTheme::adjustCheckboxStyleUsingFallbackTheme(RenderStyle* style, Elem bool RenderTheme::paintRadioUsingFallbackTheme(RenderObject* o, const PaintInfo& i, const IntRect& r) { + if (i.context->paintingDisabled()) + return false; blink::WebFallbackThemeEngine::ExtraParams extraParams; blink::WebCanvas* canvas = i.context->canvas(); extraParams.button.checked = isChecked(o); @@ -1289,7 +1196,7 @@ bool RenderTheme::paintRadioUsingFallbackTheme(RenderObject* o, const PaintInfo& unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); i.context->translate(unzoomedRect.x(), unzoomedRect.y()); - i.context->scale(FloatSize(zoomLevel, zoomLevel)); + i.context->scale(zoomLevel, zoomLevel); i.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTheme.h b/chromium/third_party/WebKit/Source/core/rendering/RenderTheme.h index 30a1c143153..4e8661e50b8 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTheme.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTheme.h @@ -37,12 +37,9 @@ namespace WebCore { -class CSSStyleSheet; class Element; class FileList; class HTMLInputElement; -class PopupMenu; -class RenderMenuList; class RenderMeter; class RenderProgress; @@ -65,7 +62,7 @@ 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(RenderStyle*, Element*, const CachedUAStyle&); + void adjustStyle(RenderStyle*, Element*, const CachedUAStyle*); // 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 @@ -97,7 +94,7 @@ public: virtual bool controlSupportsTints(const RenderObject*) const { return false; } // Whether or not the control has been styled enough by the author to disable the native appearance. - virtual bool isControlStyled(const RenderStyle*, const CachedUAStyle&) const; + virtual bool isControlStyled(const RenderStyle*, const CachedUAStyle*) const; // A general method asking if any control tinting is supported at all. virtual bool supportsControlTints() const { return false; } @@ -115,9 +112,6 @@ 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; - #if ENABLE(INPUT_MULTIPLE_FIELDS_UI) // A method asking if the platform is able to show a calendar picker for a given input type. virtual bool supportsCalendarPicker(const AtomicString&) const; @@ -139,11 +133,12 @@ public: virtual Color platformActiveTextSearchHighlightColor() const; virtual Color platformInactiveTextSearchHighlightColor() const; - static Color focusRingColor(); + Color focusRingColor() const; virtual Color platformFocusRingColor() const { return Color(0, 0, 0); } - static void setCustomFocusRingColor(const Color&); + void setCustomFocusRingColor(const Color&); static Color tapHighlightColor(); virtual Color platformTapHighlightColor() const { return RenderTheme::defaultTapHighlightColor; } + virtual Color platformDefaultCompositionBackgroundColor() const { return defaultCompositionBackgroundColor; } virtual void platformColorsDidChange(); virtual double caretBlinkInterval() const { return 0.5; } @@ -173,9 +168,6 @@ public: virtual double animationDurationForProgressBar(RenderProgress*) const; // Media controls - virtual bool supportsClosedCaptioning() const { return false; } - virtual bool hasOwnDisabledStateHandlingFor(ControlPart) const { return false; } - virtual bool usesVerticalVolumeSlider() const { return true; } virtual String formatMediaControlsTime(float time) const; virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const; @@ -201,6 +193,8 @@ public: virtual bool shouldOpenPickerWithF4Key() const; + virtual bool supportsSelectionForegroundColors() const { return true; } + protected: // The platform selection color. virtual Color platformActiveSelectionBackgroundColor() const; @@ -215,8 +209,6 @@ protected: // A method asking if the theme is able to draw the focus ring. virtual bool supportsFocusRing(const RenderStyle*) const; - virtual bool supportsSelectionForegroundColors() const { return true; } - virtual bool supportsListBoxSelectionForegroundColors() const { return true; } #if !USE(NEW_THEME) // Methods for each appearance value. @@ -249,11 +241,6 @@ protected: virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&) { return true; } -#if ENABLE(INPUT_SPEECH) - virtual void adjustInputFieldSpeechButtonStyle(RenderStyle*, Element*) const; - virtual bool paintInputFieldSpeechButton(RenderObject*, const PaintInfo&, const IntRect&); -#endif - virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&) { return true; } virtual void adjustSliderThumbStyle(RenderStyle*, Element*) const; @@ -275,15 +262,11 @@ protected: virtual bool paintMediaPlayButton(RenderObject*, const PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaOverlayPlayButton(RenderObject*, const PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaMuteButton(RenderObject*, const PaintInfo&, const IntRect&) { return true; } - virtual bool paintMediaSeekBackButton(RenderObject*, const PaintInfo&, const IntRect&) { return true; } - virtual bool paintMediaSeekForwardButton(RenderObject*, const PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaSliderTrack(RenderObject*, const PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaSliderThumb(RenderObject*, const PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaVolumeSliderContainer(RenderObject*, const PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&) { return true; } - virtual bool paintMediaRewindButton(RenderObject*, const PaintInfo&, const IntRect&) { return true; } - virtual bool paintMediaReturnToRealtimeButton(RenderObject*, const PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaControlsBackground(RenderObject*, const PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaCurrentTime(RenderObject*, const PaintInfo&, const IntRect&) { return true; } @@ -314,20 +297,15 @@ public: bool isReadOnlyControl(const RenderObject*) const; private: - mutable Color m_activeSelectionBackgroundColor; - mutable Color m_inactiveSelectionBackgroundColor; - mutable Color m_activeSelectionForegroundColor; - mutable Color m_inactiveSelectionForegroundColor; - - mutable Color m_activeListBoxSelectionBackgroundColor; - mutable Color m_inactiveListBoxSelectionBackgroundColor; - mutable Color m_activeListBoxSelectionForegroundColor; - mutable Color m_inactiveListBoxSelectionForegroundColor; + Color m_customFocusRingColor; + bool m_hasCustomFocusRingColor; // This color is expected to be drawn on a semi-transparent overlay, // making it more transparent than its alpha value indicates. static const RGBA32 defaultTapHighlightColor = 0x66000000; + static const RGBA32 defaultCompositionBackgroundColor = 0xFFFFDD55; + #if USE(NEW_THEME) Theme* m_platformTheme; // The platform-specific theme. #endif diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumAndroid.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumAndroid.cpp index 4cad9a6c0a6..0c4040af05b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumAndroid.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumAndroid.cpp @@ -26,9 +26,9 @@ #include "config.h" #include "core/rendering/RenderThemeChromiumAndroid.h" -#include "CSSValueKeywords.h" -#include "InputTypeNames.h" -#include "UserAgentStyleSheets.h" +#include "core/CSSValueKeywords.h" +#include "core/InputTypeNames.h" +#include "core/UserAgentStyleSheets.h" #include "core/rendering/PaintInfo.h" #include "core/rendering/RenderMediaControls.h" #include "core/rendering/RenderObject.h" @@ -38,7 +38,7 @@ #include "platform/graphics/Color.h" #include "platform/scroll/ScrollbarTheme.h" #include "public/platform/Platform.h" -#include "public/platform/default/WebThemeEngine.h" +#include "public/platform/WebThemeEngine.h" #include "wtf/StdLibExtras.h" namespace WebCore { @@ -58,16 +58,6 @@ RenderThemeChromiumAndroid::~RenderThemeChromiumAndroid() { } -Color RenderThemeChromiumAndroid::systemColor(CSSValueID cssValueId) const -{ - if (isRunningLayoutTest() && cssValueId == CSSValueButtonface) { - // Match Linux button color in layout tests. - static const Color linuxButtonGrayColor(0xffdddddd); - return linuxButtonGrayColor; - } - return RenderTheme::systemColor(cssValueId); -} - String RenderThemeChromiumAndroid::extraMediaControlsStyleSheet() { return String(mediaControlsAndroidUserAgentStyleSheet, sizeof(mediaControlsAndroidUserAgentStyleSheet)); @@ -91,11 +81,6 @@ void RenderThemeChromiumAndroid::adjustInnerSpinButtonStyle(RenderStyle* style, } } -bool RenderThemeChromiumAndroid::paintMediaOverlayPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) -{ - return RenderMediaControls::paintMediaControlsPart(MediaOverlayPlayButton, object, paintInfo, rect); -} - int RenderThemeChromiumAndroid::menuListArrowPadding() const { // We cannot use the scrollbar thickness here, as it's width is 0 on Android. diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumAndroid.h b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumAndroid.h index 93abb212e22..9889dc0b5f5 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumAndroid.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumAndroid.h @@ -30,19 +30,15 @@ namespace WebCore { -class RenderThemeChromiumAndroid : public RenderThemeChromiumDefault { +class RenderThemeChromiumAndroid FINAL : public RenderThemeChromiumDefault { public: static PassRefPtr<RenderTheme> create(); virtual String extraDefaultStyleSheet() OVERRIDE; - virtual Color systemColor(CSSValueID) const OVERRIDE; - virtual void adjustInnerSpinButtonStyle(RenderStyle*, Element*) const OVERRIDE; virtual bool delegatesMenuListRendering() const OVERRIDE { return true; } - virtual bool paintMediaOverlayPlayButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual String extraMediaControlsStyleSheet() OVERRIDE; virtual Color platformTapHighlightColor() const OVERRIDE diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumDefault.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumDefault.cpp index de62300e085..3f65622e8fc 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumDefault.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumDefault.cpp @@ -25,8 +25,8 @@ #include "config.h" #include "core/rendering/RenderThemeChromiumDefault.h" -#include "CSSValueKeywords.h" -#include "UserAgentStyleSheets.h" +#include "core/CSSValueKeywords.h" +#include "core/UserAgentStyleSheets.h" #include "core/rendering/PaintInfo.h" #include "core/rendering/RenderObject.h" #include "core/rendering/RenderProgress.h" @@ -34,9 +34,9 @@ #include "platform/graphics/Color.h" #include "platform/graphics/GraphicsContext.h" #include "platform/graphics/GraphicsContextStateSaver.h" -#include "public/platform/default/WebThemeEngine.h" #include "public/platform/Platform.h" #include "public/platform/WebRect.h" +#include "public/platform/WebThemeEngine.h" #include "wtf/StdLibExtras.h" namespace WebCore { @@ -220,11 +220,6 @@ void RenderThemeChromiumDefault::adjustSliderThumbSize(RenderStyle* style, Eleme RenderThemeChromiumSkia::adjustSliderThumbSize(style, element); } -bool RenderThemeChromiumDefault::supportsControlTints() const -{ - return true; -} - void RenderThemeChromiumDefault::setCaretBlinkInterval(double interval) { m_caretBlinkInterval = interval; @@ -249,19 +244,22 @@ void RenderThemeChromiumDefault::setSelectionColors( bool RenderThemeChromiumDefault::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& rect) { + if (i.context->paintingDisabled()) + return false; blink::WebThemeEngine::ExtraParams extraParams; blink::WebCanvas* canvas = i.context->canvas(); extraParams.button.checked = isChecked(o); extraParams.button.indeterminate = isIndeterminate(o); float zoomLevel = o->style()->effectiveZoom(); - GraphicsContextStateSaver stateSaver(*i.context); + GraphicsContextStateSaver stateSaver(*i.context, false); IntRect unzoomedRect = rect; if (zoomLevel != 1) { + stateSaver.save(); unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); i.context->translate(unzoomedRect.x(), unzoomedRect.y()); - i.context->scale(FloatSize(zoomLevel, zoomLevel)); + i.context->scale(zoomLevel, zoomLevel); i.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); } @@ -284,6 +282,8 @@ void RenderThemeChromiumDefault::setCheckboxSize(RenderStyle* style) const bool RenderThemeChromiumDefault::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& rect) { + if (i.context->paintingDisabled()) + return false; blink::WebThemeEngine::ExtraParams extraParams; blink::WebCanvas* canvas = i.context->canvas(); extraParams.button.checked = isChecked(o); @@ -307,6 +307,8 @@ void RenderThemeChromiumDefault::setRadioSize(RenderStyle* style) const bool RenderThemeChromiumDefault::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& rect) { + if (i.context->paintingDisabled()) + return false; blink::WebThemeEngine::ExtraParams extraParams; blink::WebCanvas* canvas = i.context->canvas(); extraParams.button.hasBorder = true; @@ -324,6 +326,8 @@ bool RenderThemeChromiumDefault::paintTextField(RenderObject* o, const PaintInfo // so return true to draw CSS border and background. if (o->style()->hasBorderRadius() || o->style()->hasBackgroundImage()) return true; + if (i.context->paintingDisabled()) + return false; ControlPart part = o->style()->appearance(); @@ -333,8 +337,7 @@ bool RenderThemeChromiumDefault::paintTextField(RenderObject* o, const PaintInfo blink::WebCanvas* canvas = i.context->canvas(); - // Fallback to white if the specified color object is invalid. - Color backgroundColor = o->resolveColor(CSSPropertyBackgroundColor, Color::white); + Color backgroundColor = o->resolveColor(CSSPropertyBackgroundColor); extraParams.textField.backgroundColor = backgroundColor.rgb(); blink::Platform::current()->themeEngine()->paint(canvas, blink::WebThemeEngine::PartTextField, getWebThemeState(this, o), blink::WebRect(rect), &extraParams); @@ -343,7 +346,7 @@ bool RenderThemeChromiumDefault::paintTextField(RenderObject* o, const PaintInfo bool RenderThemeChromiumDefault::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& rect) { - if (!o->isBox()) + if (!o->isBox() || i.context->paintingDisabled()) return false; const int right = rect.x() + rect.width(); @@ -388,7 +391,7 @@ bool RenderThemeChromiumDefault::paintMenuList(RenderObject* o, const PaintInfo& bool RenderThemeChromiumDefault::paintMenuListButton(RenderObject* o, const PaintInfo& i, const IntRect& rect) { - if (!o->isBox()) + if (!o->isBox() || i.context->paintingDisabled()) return false; const int right = rect.x() + rect.width(); @@ -422,6 +425,8 @@ bool RenderThemeChromiumDefault::paintMenuListButton(RenderObject* o, const Pain bool RenderThemeChromiumDefault::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& rect) { + if (i.context->paintingDisabled()) + return false; blink::WebThemeEngine::ExtraParams extraParams; blink::WebCanvas* canvas = i.context->canvas(); extraParams.slider.vertical = o->style()->appearance() == SliderVerticalPart; @@ -430,13 +435,14 @@ bool RenderThemeChromiumDefault::paintSliderTrack(RenderObject* o, const PaintIn // FIXME: Mock theme doesn't handle zoomed sliders. float zoomLevel = useMockTheme() ? 1 : o->style()->effectiveZoom(); - GraphicsContextStateSaver stateSaver(*i.context); + GraphicsContextStateSaver stateSaver(*i.context, false); IntRect unzoomedRect = rect; if (zoomLevel != 1) { + stateSaver.save(); unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); i.context->translate(unzoomedRect.x(), unzoomedRect.y()); - i.context->scale(FloatSize(zoomLevel, zoomLevel)); + i.context->scale(zoomLevel, zoomLevel); i.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); } @@ -447,6 +453,8 @@ bool RenderThemeChromiumDefault::paintSliderTrack(RenderObject* o, const PaintIn bool RenderThemeChromiumDefault::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& rect) { + if (i.context->paintingDisabled()) + return false; blink::WebThemeEngine::ExtraParams extraParams; blink::WebCanvas* canvas = i.context->canvas(); extraParams.slider.vertical = o->style()->appearance() == SliderThumbVerticalPart; @@ -454,13 +462,14 @@ bool RenderThemeChromiumDefault::paintSliderThumb(RenderObject* o, const PaintIn // FIXME: Mock theme doesn't handle zoomed sliders. float zoomLevel = useMockTheme() ? 1 : o->style()->effectiveZoom(); - GraphicsContextStateSaver stateSaver(*i.context); + GraphicsContextStateSaver stateSaver(*i.context, false); IntRect unzoomedRect = rect; if (zoomLevel != 1) { + stateSaver.save(); unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); i.context->translate(unzoomedRect.x(), unzoomedRect.y()); - i.context->scale(FloatSize(zoomLevel, zoomLevel)); + i.context->scale(zoomLevel, zoomLevel); i.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); } @@ -478,9 +487,11 @@ void RenderThemeChromiumDefault::adjustInnerSpinButtonStyle(RenderStyle* style, bool RenderThemeChromiumDefault::paintInnerSpinButton(RenderObject* o, const PaintInfo& i, const IntRect& rect) { + if (i.context->paintingDisabled()) + return false; blink::WebThemeEngine::ExtraParams extraParams; blink::WebCanvas* canvas = i.context->canvas(); - extraParams.innerSpin.spinUp = (controlStatesForRenderer(o) & SpinUpState); + extraParams.innerSpin.spinUp = (controlStatesForRenderer(o) & SpinUpControlState); extraParams.innerSpin.readOnly = isReadOnlyControl(o); blink::Platform::current()->themeEngine()->paint(canvas, blink::WebThemeEngine::PartInnerSpinButton, getWebThemeState(this, o), blink::WebRect(rect), &extraParams); @@ -491,6 +502,8 @@ bool RenderThemeChromiumDefault::paintProgressBar(RenderObject* o, const PaintIn { if (!o->isProgress()) return true; + if (i.context->paintingDisabled()) + return false; RenderProgress* renderProgress = toRenderProgress(o); IntRect valueRect = progressValueRectFor(renderProgress, rect); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumDefault.h b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumDefault.h index 74527e0732d..e69546895ea 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumDefault.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumDefault.h @@ -36,12 +36,12 @@ namespace WebCore { class RenderThemeChromiumDefault : public RenderThemeChromiumSkia { public: static PassRefPtr<RenderTheme> create(); - virtual String extraDefaultStyleSheet(); + virtual String extraDefaultStyleSheet() OVERRIDE; - virtual Color systemColor(CSSValueID) const; + virtual Color systemColor(CSSValueID) const OVERRIDE; // A method asking if the control changes its tint when the window has focus or not. - virtual bool controlSupportsTints(const RenderObject*) const; + virtual bool controlSupportsTints(const RenderObject*) const OVERRIDE; virtual bool supportsFocusRing(const RenderStyle*) const OVERRIDE; @@ -51,23 +51,23 @@ public: virtual Color inactiveListBoxSelectionBackgroundColor() const; virtual Color inactiveListBoxSelectionForegroundColor() const; - virtual Color platformActiveSelectionBackgroundColor() const; - virtual Color platformInactiveSelectionBackgroundColor() const; - virtual Color platformActiveSelectionForegroundColor() const; - virtual Color platformInactiveSelectionForegroundColor() const; + virtual Color platformActiveSelectionBackgroundColor() const OVERRIDE; + virtual Color platformInactiveSelectionBackgroundColor() const OVERRIDE; + virtual Color platformActiveSelectionForegroundColor() const OVERRIDE; + virtual Color platformInactiveSelectionForegroundColor() const OVERRIDE; virtual IntSize sliderTickSize() const OVERRIDE; virtual int sliderTickOffsetFromTrackCenter() const OVERRIDE; - virtual void adjustSliderThumbSize(RenderStyle*, Element*) const; + virtual void adjustSliderThumbSize(RenderStyle*, Element*) const OVERRIDE; static void setCaretBlinkInterval(double); - virtual double caretBlinkIntervalInternal() const; + virtual double caretBlinkIntervalInternal() const OVERRIDE; - virtual bool paintCheckbox(RenderObject*, const PaintInfo&, const IntRect&); - virtual void setCheckboxSize(RenderStyle*) const; + virtual bool paintCheckbox(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual void setCheckboxSize(RenderStyle*) const OVERRIDE; - virtual bool paintRadio(RenderObject*, const PaintInfo&, const IntRect&); - virtual void setRadioSize(RenderStyle*) const; + virtual bool paintRadio(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual void setRadioSize(RenderStyle*) const OVERRIDE; virtual bool paintButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; @@ -76,12 +76,12 @@ public: virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual void adjustInnerSpinButtonStyle(RenderStyle*, Element*) const; - virtual bool paintInnerSpinButton(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustInnerSpinButtonStyle(RenderStyle*, Element*) const OVERRIDE; + virtual bool paintInnerSpinButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual bool popsMenuBySpaceOrReturn() const OVERRIDE { return true; } + virtual bool popsMenuBySpaceOrReturn() const OVERRIDE FINAL { return true; } - virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; virtual bool shouldOpenPickerWithF4Key() const OVERRIDE; @@ -93,9 +93,6 @@ protected: virtual bool shouldUseFallbackTheme(RenderStyle*) const OVERRIDE; private: - // A general method asking if any control tinting is supported at all. - virtual bool supportsControlTints() const; - static double m_caretBlinkInterval; static unsigned m_activeSelectionBackgroundColor; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumFontProvider.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumFontProvider.cpp index 527f8558f78..b8083e015fe 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumFontProvider.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumFontProvider.cpp @@ -46,9 +46,9 @@ float RenderThemeChromiumFontProvider::s_defaultFontSize = 16.0; // FIXME: The only case where we know we don't match IE is for ANSI encodings. // IE uses MS Shell Dlg there, which we render incorrectly at certain pixel // sizes (e.g. 15px). So, for now we just use Arial. -const String& RenderThemeChromiumFontProvider::defaultGUIFont() +const AtomicString& RenderThemeChromiumFontProvider::defaultGUIFont() { - DEFINE_STATIC_LOCAL(String, fontFace, ("Arial")); + DEFINE_STATIC_LOCAL(const AtomicString, fontFace, ("Arial", AtomicString::ConstructFromLiteral)); return fontFace; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumFontProvider.h b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumFontProvider.h index 57589c2a397..e31322461b2 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumFontProvider.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumFontProvider.h @@ -26,11 +26,7 @@ #ifndef RenderThemeChromiumFontProvider_h #define RenderThemeChromiumFontProvider_h -#include "CSSValueKeywords.h" - -namespace WTF { -class String; -} +#include "core/CSSValueKeywords.h" namespace WebCore { @@ -42,7 +38,7 @@ public: static void setDefaultFontSize(int); protected: - static const WTF::String& defaultGUIFont(); + static const WTF::AtomicString& defaultGUIFont(); static float s_defaultFontSize; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumFontProviderLinux.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumFontProviderLinux.cpp index 3d1d0260d0a..35e16714738 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumFontProviderLinux.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumFontProviderLinux.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "core/rendering/RenderThemeChromiumFontProvider.h" -#include "CSSValueKeywords.h" +#include "core/CSSValueKeywords.h" #include "platform/fonts/FontDescription.h" #include "wtf/StdLibExtras.h" @@ -65,7 +65,7 @@ void RenderThemeChromiumFontProvider::systemFont(CSSValueID valueID, FontDescrip fontDescription.setIsAbsoluteSize(true); fontDescription.setGenericFamily(FontDescription::NoFamily); fontDescription.setWeight(FontWeightNormal); - fontDescription.setItalic(false); + fontDescription.setStyle(FontStyleNormal); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumFontProviderWin.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumFontProviderWin.cpp index 18305cc31d6..0db04403219 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumFontProviderWin.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumFontProviderWin.cpp @@ -26,13 +26,12 @@ #include "config.h" #include "core/rendering/RenderThemeChromiumFontProvider.h" -#include <windows.h> - -#include "CSSValueKeywords.h" +#include "core/CSSValueKeywords.h" #include "platform/fonts/FontDescription.h" #include "platform/win/HWndDC.h" #include "platform/win/SystemInfo.h" #include "wtf/text/WTFString.h" +#include <windows.h> #define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \ offsetof(structName, member) + \ @@ -175,7 +174,7 @@ void RenderThemeChromiumFontProvider::systemFont(CSSValueID valueID, FontDescrip cachedDesc->setGenericFamily(FontDescription::NoFamily); cachedDesc->setSpecifiedSize(fontSize); cachedDesc->setWeight(FontWeightNormal); - cachedDesc->setItalic(false); + cachedDesc->setStyle(FontStyleNormal); } fontDescription = *cachedDesc; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumMac.h b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumMac.h index 371ecc6c717..3dc8de4841d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumMac.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumMac.h @@ -32,7 +32,7 @@ OBJC_CLASS WebCoreRenderThemeNotificationObserver; namespace WebCore { -class RenderThemeChromiumMac : public RenderTheme { +class RenderThemeChromiumMac FINAL : public RenderTheme { public: static PassRefPtr<RenderTheme> create(); @@ -44,10 +44,11 @@ public: virtual void adjustRepaintRect(const RenderObject*, IntRect&) OVERRIDE; - virtual bool isControlStyled(const RenderStyle*, const CachedUAStyle&) const OVERRIDE; + virtual bool isControlStyled(const RenderStyle*, const CachedUAStyle*) const OVERRIDE; virtual Color platformActiveSelectionBackgroundColor() const OVERRIDE; virtual Color platformInactiveSelectionBackgroundColor() const OVERRIDE; + virtual Color platformActiveSelectionForegroundColor() const OVERRIDE; virtual Color platformActiveListBoxSelectionBackgroundColor() const OVERRIDE; virtual Color platformActiveListBoxSelectionForegroundColor() const OVERRIDE; virtual Color platformInactiveListBoxSelectionBackgroundColor() const OVERRIDE; @@ -88,41 +89,39 @@ public: virtual Color systemColor(CSSValueID) const OVERRIDE; + virtual bool supportsSelectionForegroundColors() const OVERRIDE { return false; } + protected: RenderThemeChromiumMac(); virtual ~RenderThemeChromiumMac(); - virtual bool supportsSelectionForegroundColors() const OVERRIDE { return false; } - - virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&); - - virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustMenuListStyle(RenderStyle*, Element*) const; + virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustMenuListButtonStyle(RenderStyle*, Element*) const; + virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual void adjustMenuListStyle(RenderStyle*, Element*) const OVERRIDE; - virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual void adjustMenuListButtonStyle(RenderStyle*, Element*) const OVERRIDE; - virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldStyle(RenderStyle*, Element*) const; + virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual void adjustSearchFieldCancelButtonStyle(RenderStyle*, Element*) const; - virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual void adjustSearchFieldStyle(RenderStyle*, Element*) const OVERRIDE; - virtual void adjustSearchFieldDecorationStyle(RenderStyle*, Element*) const; - virtual bool paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustSearchFieldCancelButtonStyle(RenderStyle*, Element*) const OVERRIDE; + virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual void adjustSearchFieldResultsDecorationStyle(RenderStyle*, Element*) const; - virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustSearchFieldDecorationStyle(RenderStyle*, Element*) const OVERRIDE; + virtual bool paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual bool supportsClosedCaptioning() const { return true; } + virtual void adjustSearchFieldResultsDecorationStyle(RenderStyle*, Element*) const OVERRIDE; + virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; private: virtual String fileListNameForWidth(Locale&, const FileList*, const Font&, int width) const OVERRIDE; @@ -151,7 +150,6 @@ private: const IntSize* popupButtonSizes() const; const int* popupButtonMargins() const; const int* popupButtonPadding(NSControlSize) const; - void paintMenuListButtonGradients(RenderObject*, const PaintInfo&, const IntRect&); const IntSize* menuListSizes() const; const IntSize* searchFieldSizes() const; @@ -174,21 +172,20 @@ private: protected: virtual void adjustMediaSliderThumbSize(RenderStyle*) const; - virtual bool paintMediaPlayButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaMuteButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); - virtual String extraFullScreenStyleSheet(); - - virtual bool paintMediaSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaVolumeSliderContainer(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool hasOwnDisabledStateHandlingFor(ControlPart) const { return true; } - virtual bool usesVerticalVolumeSlider() const { return false; } - virtual String formatMediaControlsTime(float time) const; - virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const; - virtual bool paintMediaFullscreenButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintMediaPlayButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual bool paintMediaOverlayPlayButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual bool paintMediaMuteButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual bool paintMediaSliderTrack(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual String extraFullScreenStyleSheet() OVERRIDE; + + virtual bool paintMediaSliderThumb(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual bool paintMediaVolumeSliderContainer(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual bool paintMediaVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual bool paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual String formatMediaControlsTime(float time) const OVERRIDE; + virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const OVERRIDE; + virtual bool paintMediaFullscreenButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; // Controls color values returned from platformFocusRingColor(). systemColor() will be used when false. bool usesTestModeFocusRingColor() const; @@ -199,7 +196,7 @@ protected: private: virtual void updateActiveState(NSCell*, const RenderObject*); - virtual String extraDefaultStyleSheet(); + virtual String extraDefaultStyleSheet() OVERRIDE; virtual bool shouldShowPlaceholderWhenFocused() const OVERRIDE; mutable RetainPtr<NSPopUpButtonCell> m_popupButton; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumMac.mm b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumMac.mm index 82f39e25601..a25be5a7c89 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumMac.mm +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumMac.mm @@ -34,7 +34,6 @@ #import "core/html/TimeRanges.h" #import "core/html/shadow/MediaControlElements.h" #import "core/frame/FrameView.h" -#import "core/platform/mac/ThemeMac.h" #import "core/rendering/PaintInfo.h" #import "core/rendering/RenderLayer.h" #import "core/rendering/RenderMedia.h" @@ -50,9 +49,9 @@ #import "platform/graphics/GraphicsContextStateSaver.h" #import "platform/graphics/Image.h" #import "platform/graphics/ImageBuffer.h" -#import "platform/graphics/cg/GraphicsContextCG.h" #import "platform/mac/ColorMac.h" #import "platform/mac/LocalCurrentGraphicsContext.h" +#import "platform/mac/ThemeMac.h" #import "platform/mac/WebCoreNSCellExtras.h" #import "platform/text/PlatformLocale.h" #import "platform/text/StringTruncator.h" @@ -194,6 +193,11 @@ Color RenderThemeChromiumMac::platformInactiveSelectionBackgroundColor() const return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); } +Color RenderThemeChromiumMac::platformActiveSelectionForegroundColor() const +{ + return Color::black; +} + Color RenderThemeChromiumMac::platformActiveListBoxSelectionBackgroundColor() const { NSColor* color = [[NSColor alternateSelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; @@ -212,8 +216,9 @@ Color RenderThemeChromiumMac::platformInactiveListBoxSelectionForegroundColor() Color RenderThemeChromiumMac::platformFocusRingColor() const { + static const RGBA32 oldAquaFocusRingColor = 0xFF7DADD9; if (usesTestModeFocusRingColor()) - return oldAquaFocusRingColor(); + return oldAquaFocusRingColor; return systemColor(CSSValueWebkitFocusRingColor); } @@ -306,7 +311,7 @@ void RenderThemeChromiumMac::systemFont(CSSValueID cssValueId, FontDescription& cachedDesc->firstFamily().setFamily([font webCoreFamilyName]); cachedDesc->setSpecifiedSize([font pointSize]); cachedDesc->setWeight(toFontWeight([fontManager weightOfFont:font])); - cachedDesc->setItalic([fontManager traitsOfFont:font] & NSItalicFontMask); + cachedDesc->setStyle([fontManager traitsOfFont:font] & NSItalicFontMask ? FontStyleItalic : FontStyleNormal); } fontDescription = *cachedDesc; } @@ -394,6 +399,7 @@ Color RenderThemeChromiumMac::systemColor(CSSValueID cssValueId) const } Color color; + bool needsFallback = false; switch (cssValueId) { case CSSValueActiveborder: color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]); @@ -406,6 +412,7 @@ Color RenderThemeChromiumMac::systemColor(CSSValueID cssValueId) const break; case CSSValueBackground: // Use theme independent default + needsFallback = true; break; case CSSValueButtonface: // We use this value instead of NSColor's controlColor to avoid website incompatibilities. @@ -491,22 +498,23 @@ Color RenderThemeChromiumMac::systemColor(CSSValueID cssValueId) const color = convertNSColorToColor([NSColor windowFrameTextColor]); break; default: + needsFallback = true; break; } - if (!color.isValid()) + if (needsFallback) color = RenderTheme::systemColor(cssValueId); - if (color.isValid()) - m_systemColorCache.set(cssValueId, color.rgb()); + m_systemColorCache.set(cssValueId, color.rgb()); return color; } -bool RenderThemeChromiumMac::isControlStyled(const RenderStyle* style, const CachedUAStyle& uaStyle) const +bool RenderThemeChromiumMac::isControlStyled(const RenderStyle* style, const CachedUAStyle* uaStyle) const { + ASSERT(uaStyle); if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart) - return style->border() != uaStyle.border || style->boxShadow(); + return style->border() != uaStyle->border || style->boxShadow(); // FIXME: This is horrible, but there is not much else that can be done. Menu lists cannot draw properly when // scaled. They can't really draw properly when transformed either. We can't detect the transform case at style @@ -733,7 +741,7 @@ void RenderThemeChromiumMac::setFontFromControlSize(RenderStyle* style, NSContro style->setLineHeight(RenderStyle::initialLineHeight()); if (style->setFontDescription(fontDescription)) - style->font().update(0); + style->font().update(nullptr); } NSControlSize RenderThemeChromiumMac::controlSizeForSystemFont(RenderStyle* style) const @@ -903,7 +911,7 @@ bool RenderThemeChromiumMac::paintMenuList(RenderObject* o, const PaintInfo& pai inflatedRect.setWidth(inflatedRect.width() / zoomLevel); inflatedRect.setHeight(inflatedRect.height() / zoomLevel); paintInfo.context->translate(inflatedRect.x(), inflatedRect.y()); - paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->scale(zoomLevel, zoomLevel); paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); } @@ -1096,10 +1104,11 @@ bool RenderThemeChromiumMac::paintProgressBar(RenderObject* renderObject, const if (!renderProgress->style()->isLeftToRightDirection()) { paintInfo.context->translate(2 * inflatedRect.x() + inflatedRect.width(), 0); - paintInfo.context->scale(FloatSize(-1, 1)); + paintInfo.context->scale(-1, 1); } - paintInfo.context->drawImageBuffer(imageBuffer.get(), inflatedRect.location()); + paintInfo.context->drawImageBuffer(imageBuffer.get(), + FloatRect(inflatedRect.location(), imageBuffer->size())); return false; } @@ -1115,112 +1124,12 @@ const int styledPopupPaddingLeft = 8; const int styledPopupPaddingTop = 1; const int styledPopupPaddingBottom = 2; -static void TopGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) -{ - static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f }; - static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f }; - float a = inData[0]; - int i = 0; - for (i = 0; i < 4; i++) - outData[i] = (1.0f - a) * dark[i] + a * light[i]; -} - -static void BottomGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) -{ - static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f }; - static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f }; - float a = inData[0]; - int i = 0; - for (i = 0; i < 4; i++) - outData[i] = (1.0f - a) * dark[i] + a * light[i]; -} - -static void MainGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) -{ - static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f }; - static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - float a = inData[0]; - int i = 0; - for (i = 0; i < 4; i++) - outData[i] = (1.0f - a) * dark[i] + a * light[i]; -} - -void RenderThemeChromiumMac::paintMenuListButtonGradients(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) -{ - if (r.isEmpty()) - return; - - ContextContainer cgContextContainer(paintInfo.context); - CGContextRef context = cgContextContainer.context(); - - GraphicsContextStateSaver stateSaver(*paintInfo.context); - - RoundedRect border = o->style()->getRoundedBorderFor(r, o->view()); - int radius = border.radii().topLeft().width(); - - CGColorSpaceRef cspace = deviceRGBColorSpaceRef(); - - FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f); - struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL }; - RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks)); - RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false)); - - FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f); - struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL }; - RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks)); - RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false)); - - struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL }; - RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); - RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false)); - - RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false)); - - RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.maxX(), r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false)); - - { - GraphicsContextStateSaver stateSaver(*paintInfo.context); - CGContextClipToRect(context, r); - paintInfo.context->clipRoundedRect(border); - context = cgContextContainer.context(); - CGContextDrawShading(context, mainShading.get()); - } - - { - GraphicsContextStateSaver stateSaver(*paintInfo.context); - CGContextClipToRect(context, topGradient); - paintInfo.context->clipRoundedRect(RoundedRect(enclosingIntRect(topGradient), border.radii().topLeft(), border.radii().topRight(), IntSize(), IntSize())); - context = cgContextContainer.context(); - CGContextDrawShading(context, topShading.get()); - } - - if (!bottomGradient.isEmpty()) { - GraphicsContextStateSaver stateSaver(*paintInfo.context); - CGContextClipToRect(context, bottomGradient); - paintInfo.context->clipRoundedRect(RoundedRect(enclosingIntRect(bottomGradient), IntSize(), IntSize(), border.radii().bottomLeft(), border.radii().bottomRight())); - context = cgContextContainer.context(); - CGContextDrawShading(context, bottomShading.get()); - } - - { - GraphicsContextStateSaver stateSaver(*paintInfo.context); - CGContextClipToRect(context, r); - paintInfo.context->clipRoundedRect(border); - context = cgContextContainer.context(); - CGContextDrawShading(context, leftShading.get()); - CGContextDrawShading(context, rightShading.get()); - } -} - bool RenderThemeChromiumMac::paintMenuListButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(), r.y() + o->style()->borderTopWidth(), r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(), r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth()); - // Draw the gradients to give the styled popup menu a button appearance - paintMenuListButtonGradients(o, paintInfo, bounds); - // Since we actually know the size of the control here, we restrict the font scale to make sure the arrows will fit vertically in the bounds float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows)); float centerY = bounds.y() + bounds.height() / 2.0f; @@ -1252,24 +1161,6 @@ bool RenderThemeChromiumMac::paintMenuListButton(RenderObject* o, const PaintInf // Draw the bottom arrow paintInfo.context->drawConvexPolygon(3, arrow2, true); - - Color leftSeparatorColor(0, 0, 0, 40); - Color rightSeparatorColor(255, 255, 255, 40); - - // FIXME: Should the separator thickness and space be scaled up by fontScale? - int separatorSpace = 2; // Deliberately ignores zoom since it looks nicer if it stays thin. - int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft * o->style()->effectiveZoom()); // FIXME: Round? - - // Draw the separator to the left of the arrows - paintInfo.context->setStrokeThickness(1.0f); // Deliberately ignores zoom since it looks nicer if it stays thin. - paintInfo.context->setStrokeStyle(SolidStroke); - paintInfo.context->setStrokeColor(leftSeparatorColor); - paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()), - IntPoint(leftEdgeOfSeparator, bounds.maxY())); - - paintInfo.context->setStrokeColor(rightSeparatorColor); - paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()), - IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.maxY())); return false; } @@ -1423,7 +1314,7 @@ bool RenderThemeChromiumMac::paintSliderTrack(RenderObject* o, const PaintInfo& GraphicsContextStateSaver stateSaver(*paintInfo.context); if (zoomLevel != 1) { paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); - paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->scale(zoomLevel, zoomLevel); paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); } @@ -1488,7 +1379,7 @@ bool RenderThemeChromiumMac::paintSliderThumb(RenderObject* o, const PaintInfo& FloatRect unzoomedRect(r.x(), r.y(), sliderThumbWidth, sliderThumbHeight); if (zoomLevel != 1.0f) { paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); - paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->scale(zoomLevel, zoomLevel); paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); } @@ -1573,7 +1464,7 @@ bool RenderThemeChromiumMac::paintSearchField(RenderObject* o, const PaintInfo& unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); - paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->scale(zoomLevel, zoomLevel); paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); } @@ -1656,6 +1547,8 @@ void RenderThemeChromiumMac::adjustSearchFieldStyle(RenderStyle* style, Element* bool RenderThemeChromiumMac::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { + if (!o->node()) + return false; Element* input = o->node()->shadowHost(); if (!input) input = toElement(o->node()); @@ -1671,7 +1564,7 @@ bool RenderThemeChromiumMac::paintSearchFieldCancelButton(RenderObject* o, const unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); - paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->scale(zoomLevel, zoomLevel); paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); } @@ -1754,6 +1647,8 @@ void RenderThemeChromiumMac::adjustSearchFieldResultsDecorationStyle(RenderStyle bool RenderThemeChromiumMac::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { + if (!o->node()) + return false; Node* input = o->node()->shadowHost(); if (!input) input = o->node(); @@ -1768,7 +1663,7 @@ bool RenderThemeChromiumMac::paintSearchFieldResultsDecoration(RenderObject* o, unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); - paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->scale(zoomLevel, zoomLevel); paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); } @@ -1940,6 +1835,11 @@ bool RenderThemeChromiumMac::paintMediaPlayButton(RenderObject* object, const Pa return RenderMediaControls::paintMediaControlsPart(MediaPlayButton, object, paintInfo, rect); } +bool RenderThemeChromiumMac::paintMediaOverlayPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) +{ + return RenderMediaControls::paintMediaControlsPart(MediaOverlayPlayButton, object, paintInfo, rect); +} + bool RenderThemeChromiumMac::paintMediaMuteButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) { return RenderMediaControls::paintMediaControlsPart(MediaMuteButton, object, paintInfo, rect); @@ -1959,7 +1859,8 @@ String RenderThemeChromiumMac::extraFullScreenStyleSheet() String RenderThemeChromiumMac::extraDefaultStyleSheet() { return RenderTheme::extraDefaultStyleSheet() + - String(themeChromiumUserAgentStyleSheet, sizeof(themeChromiumUserAgentStyleSheet)); + String(themeChromiumUserAgentStyleSheet, sizeof(themeChromiumUserAgentStyleSheet)) + + String(themeMacUserAgentStyleSheet, sizeof(themeMacUserAgentStyleSheet)); } bool RenderThemeChromiumMac::paintMediaVolumeSliderContainer(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumSkia.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumSkia.cpp index 2a7e3c2b232..f836738a38c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumSkia.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumSkia.cpp @@ -24,7 +24,7 @@ #include "config.h" #include "core/rendering/RenderThemeChromiumSkia.h" -#include "UserAgentStyleSheets.h" +#include "core/UserAgentStyleSheets.h" #include "core/rendering/PaintInfo.h" #include "core/rendering/RenderBox.h" #include "core/rendering/RenderMediaControls.h" @@ -91,11 +91,6 @@ bool RenderThemeChromiumSkia::supportsFocusRing(const RenderStyle* style) const return false; } -bool RenderThemeChromiumSkia::supportsClosedCaptioning() const -{ - return true; -} - Color RenderThemeChromiumSkia::platformActiveSelectionBackgroundColor() const { return Color(0x1e, 0x90, 0xff); @@ -227,6 +222,8 @@ IntRect RenderThemeChromiumSkia::convertToPaintingRect(RenderObject* inputRender bool RenderThemeChromiumSkia::paintSearchFieldCancelButton(RenderObject* cancelButtonObject, const PaintInfo& paintInfo, const IntRect& r) { // Get the renderer of <input> element. + if (!cancelButtonObject->node()) + return false; Node* input = cancelButtonObject->node()->shadowHost(); RenderObject* baseRenderer = input ? input->renderer() : cancelButtonObject; if (!baseRenderer->isBox()) @@ -270,6 +267,8 @@ void RenderThemeChromiumSkia::adjustSearchFieldResultsDecorationStyle(RenderStyl bool RenderThemeChromiumSkia::paintSearchFieldResultsDecoration(RenderObject* magnifierObject, const PaintInfo& paintInfo, const IntRect& r) { // Get the renderer of <input> element. + if (!magnifierObject->node()) + return false; Node* input = magnifierObject->node()->shadowHost(); RenderObject* baseRenderer = input ? input->renderer() : magnifierObject; if (!baseRenderer->isBox()) @@ -327,6 +326,11 @@ bool RenderThemeChromiumSkia::paintMediaPlayButton(RenderObject* object, const P return RenderMediaControls::paintMediaControlsPart(MediaPlayButton, object, paintInfo, rect); } +bool RenderThemeChromiumSkia::paintMediaOverlayPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) +{ + return RenderMediaControls::paintMediaControlsPart(MediaOverlayPlayButton, object, paintInfo, rect); +} + bool RenderThemeChromiumSkia::paintMediaMuteButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) { return RenderMediaControls::paintMediaControlsPart(MediaMuteButton, object, paintInfo, rect); @@ -473,7 +477,7 @@ RenderThemeChromiumSkia::DirectionFlippingScope::DirectionFlippingScope(RenderOb return; m_paintInfo.context->save(); m_paintInfo.context->translate(2 * rect.x() + rect.width(), 0); - m_paintInfo.context->scale(FloatSize(-1, 1)); + m_paintInfo.context->scale(-1, 1); } RenderThemeChromiumSkia::DirectionFlippingScope::~DirectionFlippingScope() diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumSkia.h b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumSkia.h index f3550c7aca0..c47eff77872 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumSkia.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumSkia.h @@ -39,8 +39,8 @@ public: RenderThemeChromiumSkia(); virtual ~RenderThemeChromiumSkia(); - virtual String extraDefaultStyleSheet(); - virtual String extraQuirksStyleSheet(); + virtual String extraDefaultStyleSheet() OVERRIDE; + virtual String extraQuirksStyleSheet() OVERRIDE; virtual Color platformTapHighlightColor() const OVERRIDE { @@ -48,57 +48,57 @@ public: } // A method asking if the theme's controls actually care about redrawing when hovered. - virtual bool supportsHover(const RenderStyle*) const; + virtual bool supportsHover(const RenderStyle*) const OVERRIDE FINAL; // A method asking if the theme is able to draw the focus ring. - virtual bool supportsFocusRing(const RenderStyle*) const; + virtual bool supportsFocusRing(const RenderStyle*) const OVERRIDE; - virtual bool supportsClosedCaptioning() const OVERRIDE; // The platform selection color. - virtual Color platformActiveSelectionBackgroundColor() const; - virtual Color platformInactiveSelectionBackgroundColor() const; - virtual Color platformActiveSelectionForegroundColor() const; - virtual Color platformInactiveSelectionForegroundColor() const; - virtual Color platformFocusRingColor() const; + virtual Color platformActiveSelectionBackgroundColor() const OVERRIDE; + virtual Color platformInactiveSelectionBackgroundColor() const OVERRIDE; + virtual Color platformActiveSelectionForegroundColor() const OVERRIDE; + virtual Color platformInactiveSelectionForegroundColor() const OVERRIDE; + virtual Color platformFocusRingColor() const OVERRIDE; // To change the blink interval, override caretBlinkIntervalInternal instead of this one so that we may share layout test code an intercepts. - virtual double caretBlinkInterval() const; + virtual double caretBlinkInterval() const OVERRIDE; // System fonts. - virtual void systemFont(CSSValueID, FontDescription&) const; + virtual void systemFont(CSSValueID, FontDescription&) const OVERRIDE; - virtual int minimumMenuListSize(RenderStyle*) const; + virtual int minimumMenuListSize(RenderStyle*) const OVERRIDE; - virtual void setCheckboxSize(RenderStyle*) const; + virtual void setCheckboxSize(RenderStyle*) const OVERRIDE; - virtual void setRadioSize(RenderStyle*) const; + virtual void setRadioSize(RenderStyle*) const OVERRIDE; - virtual void adjustButtonStyle(RenderStyle*, Element*) const; + virtual void adjustButtonStyle(RenderStyle*, Element*) const OVERRIDE; - virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual void adjustSearchFieldStyle(RenderStyle*, Element*) const; - virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustSearchFieldStyle(RenderStyle*, Element*) const OVERRIDE; + virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual void adjustSearchFieldCancelButtonStyle(RenderStyle*, Element*) const; - virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustSearchFieldCancelButtonStyle(RenderStyle*, Element*) const OVERRIDE; + virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual void adjustSearchFieldDecorationStyle(RenderStyle*, Element*) const; + virtual void adjustSearchFieldDecorationStyle(RenderStyle*, Element*) const OVERRIDE; - virtual void adjustSearchFieldResultsDecorationStyle(RenderStyle*, Element*) const; - virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustSearchFieldResultsDecorationStyle(RenderStyle*, Element*) const OVERRIDE; + virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual bool paintMediaSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSliderThumbSize(RenderStyle*, Element*) const; - virtual bool paintMediaSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaPlayButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool paintMediaMuteButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual String formatMediaControlsTime(float time) const; - virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const; - virtual bool paintMediaFullscreenButton(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintMediaSliderTrack(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual bool paintMediaVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual void adjustSliderThumbSize(RenderStyle*, Element*) const OVERRIDE; + virtual bool paintMediaSliderThumb(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual bool paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual bool paintMediaPlayButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual bool paintMediaOverlayPlayButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual bool paintMediaMuteButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; + virtual String formatMediaControlsTime(float time) const OVERRIDE; + virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const OVERRIDE; + virtual bool paintMediaFullscreenButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; // MenuList refers to an unstyled menulist (meaning a menulist without // background-color or border set) and MenuListButton refers to a styled @@ -109,22 +109,18 @@ public: // 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(RenderStyle*, Element*) const; - virtual void adjustMenuListButtonStyle(RenderStyle*, Element*) const; - virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&); + virtual void adjustMenuListStyle(RenderStyle*, Element*) const OVERRIDE; + virtual void adjustMenuListButtonStyle(RenderStyle*, Element*) const OVERRIDE; + virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual double animationRepeatIntervalForProgressBar(RenderProgress*) const; - virtual double animationDurationForProgressBar(RenderProgress*) const; + virtual double animationRepeatIntervalForProgressBar(RenderProgress*) const OVERRIDE; + virtual double animationDurationForProgressBar(RenderProgress*) const OVERRIDE; // These methods define the padding for the MenuList's inner block. - virtual int popupInternalPaddingLeft(RenderStyle*) const; - virtual int popupInternalPaddingRight(RenderStyle*) const; - virtual int popupInternalPaddingTop(RenderStyle*) const; - virtual int popupInternalPaddingBottom(RenderStyle*) const; - - // Media controls - virtual bool hasOwnDisabledStateHandlingFor(ControlPart) const { return true; } - virtual bool usesVerticalVolumeSlider() const { return false; } + virtual int popupInternalPaddingLeft(RenderStyle*) const OVERRIDE; + virtual int popupInternalPaddingRight(RenderStyle*) const OVERRIDE; + virtual int popupInternalPaddingTop(RenderStyle*) const OVERRIDE; + virtual int popupInternalPaddingBottom(RenderStyle*) const OVERRIDE; // Provide a way to pass the default font size from the Settings object // to the render theme. FIXME: http://b/1129186 A cleaner way would be diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumWin.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumWin.cpp deleted file mode 100644 index b1224074607..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumWin.cpp +++ /dev/null @@ -1,660 +0,0 @@ -/* - * This file is part of the WebKit project. - * - * Copyright (C) 2006 Apple Computer, Inc. - * Copyright (C) 2008, 2009 Google, Inc. - * Copyright (C) 2009 Kenneth Rohde Christiansen - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - */ - -#include "config.h" -#include "core/rendering/RenderThemeChromiumWin.h" - -#include <windows.h> -#include <uxtheme.h> -#include <vssym32.h> - -#include "CSSValueKeywords.h" -#include "HTMLNames.h" -#include "core/html/HTMLMediaElement.h" -#include "core/html/shadow/MediaControlElements.h" -#include "core/rendering/PaintInfo.h" -#include "core/rendering/RenderBox.h" -#include "core/rendering/RenderProgress.h" -#include "core/rendering/RenderSlider.h" -#include "platform/LayoutTestSupport.h" -#include "platform/fonts/FontSelector.h" -#include "platform/graphics/GraphicsContext.h" -#include "platform/graphics/win/TransparencyWin.h" -#include "platform/scroll/ScrollbarTheme.h" -#include "platform/win/SystemInfo.h" -#include "public/platform/Platform.h" -#include "public/platform/WebColor.h" -#include "public/platform/WebRect.h" -#include "public/platform/win/WebThemeEngine.h" -#include "wtf/CurrentTime.h" -#include "wtf/StdLibExtras.h" - -// FIXME: This dependency should eventually be removed. -#include <skia/ext/skia_utils_win.h> - -namespace WebCore { - -// The standard width for the menu list drop-down button when run under -// layout test mode. Use the value that's currently captured in most baselines. -static const int kStandardMenuListButtonWidth = 17; - -namespace { -// We must not create multiple ThemePainter instances. -class ThemePainter { -public: - ThemePainter(GraphicsContext* context, const IntRect& r) - { -#ifndef NDEBUG - ASSERT(!s_hasInstance); - s_hasInstance = true; -#endif - TransparencyWin::TransformMode transformMode = getTransformMode(context->getCTM()); - m_helper.init(context, getLayerMode(context, transformMode), transformMode, r); - - if (!m_helper.context()) { - // TransparencyWin doesn't have well-defined copy-ctor nor op=() - // so we re-initialize it instead of assigning a fresh istance. - // On the reinitialization, we fallback to use NoLayer mode. - // Note that the original initialization failure can be caused by - // a failure of an internal buffer allocation and NoLayer mode - // does not have such buffer allocations. - m_helper.~TransparencyWin(); - new (&m_helper) TransparencyWin(); - m_helper.init(context, TransparencyWin::NoLayer, transformMode, r); - } - } - - ~ThemePainter() - { - m_helper.composite(); -#ifndef NDEBUG - s_hasInstance = false; -#endif - } - - GraphicsContext* context() { return m_helper.context(); } - const IntRect& drawRect() { return m_helper.drawRect(); } - -private: - - static TransparencyWin::LayerMode getLayerMode(GraphicsContext* context, TransparencyWin::TransformMode transformMode) - { - if (!context->isCertainlyOpaque()) // Might have transparent background. - return TransparencyWin::WhiteLayer; - if (context->canvas()->isDrawingToLayer()) // Needs antialiasing help. - return TransparencyWin::OpaqueCompositeLayer; - // Nothing interesting. - return transformMode == TransparencyWin::KeepTransform ? TransparencyWin::NoLayer : TransparencyWin::OpaqueCompositeLayer; - } - - static TransparencyWin::TransformMode getTransformMode(const AffineTransform& matrix) - { - if (matrix.b() || matrix.c()) // Skew. - return TransparencyWin::Untransform; - if (matrix.a() != 1.0 || matrix.d() != 1.0) // Scale. - return TransparencyWin::ScaleTransform; - // Nothing interesting. - return TransparencyWin::KeepTransform; - } - - TransparencyWin m_helper; -#ifndef NDEBUG - static bool s_hasInstance; -#endif -}; - -#ifndef NDEBUG -bool ThemePainter::s_hasInstance = false; -#endif - -} // namespace - -// Internal static helper functions. We don't put them in an anonymous -// namespace so they have easier access to the WebCore namespace. - -static bool supportsFocus(ControlPart appearance) -{ - switch (appearance) { - case SquareButtonPart: - case PushButtonPart: - case ButtonPart: - case SearchFieldPart: - case TextFieldPart: - case TextAreaPart: - return true; - } - return false; -} - -static double querySystemBlinkInterval(double defaultInterval) -{ - UINT blinkTime = GetCaretBlinkTime(); - if (!blinkTime) - return defaultInterval; - if (blinkTime == INFINITE) - return 0; - return blinkTime / 1000.0; -} - -PassRefPtr<RenderTheme> RenderThemeChromiumWin::create() -{ - return adoptRef(new RenderThemeChromiumWin); -} - -RenderTheme& RenderTheme::theme() -{ - DEFINE_STATIC_REF(RenderTheme, renderTheme, (RenderThemeChromiumWin::create())); - return *renderTheme; -} - -bool RenderThemeChromiumWin::supportsFocusRing(const RenderStyle* style) const -{ - // Let webkit draw one of its halo rings around any focused element, - // except push buttons. For buttons we use the windows PBS_DEFAULTED - // styling to give it a blue border. - return style->appearance() == ButtonPart - || style->appearance() == PushButtonPart - || style->appearance() == SquareButtonPart; -} - -Color RenderThemeChromiumWin::platformActiveSelectionBackgroundColor() const -{ - if (isRunningLayoutTest()) - return Color(0x00, 0x00, 0xff); // Royal blue. - COLORREF color = GetSysColor(COLOR_HIGHLIGHT); - return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); -} - -Color RenderThemeChromiumWin::platformInactiveSelectionBackgroundColor() const -{ - if (isRunningLayoutTest()) - return Color(0x99, 0x99, 0x99); // Medium gray. - COLORREF color = GetSysColor(COLOR_GRAYTEXT); - return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); -} - -Color RenderThemeChromiumWin::platformActiveSelectionForegroundColor() const -{ - if (isRunningLayoutTest()) - return Color(0xff, 0xff, 0xcc); // Pale yellow. - COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT); - return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); -} - -Color RenderThemeChromiumWin::platformInactiveSelectionForegroundColor() const -{ - return Color::white; -} - -Color RenderThemeChromiumWin::platformActiveTextSearchHighlightColor() const -{ - return Color(0xff, 0x96, 0x32); // Orange. -} - -Color RenderThemeChromiumWin::platformInactiveTextSearchHighlightColor() const -{ - return Color(0xff, 0xff, 0x96); // Yellow. -} - -// Map a CSSValue* system color to an index understood by GetSysColor(). -static int cssValueIdToSysColorIndex(int cssValueId) -{ - switch (cssValueId) { - case CSSValueActiveborder: return COLOR_ACTIVEBORDER; - case CSSValueActivecaption: return COLOR_ACTIVECAPTION; - case CSSValueAppworkspace: return COLOR_APPWORKSPACE; - case CSSValueBackground: return COLOR_BACKGROUND; - case CSSValueButtonface: return COLOR_BTNFACE; - case CSSValueButtonhighlight: return COLOR_BTNHIGHLIGHT; - case CSSValueButtonshadow: return COLOR_BTNSHADOW; - case CSSValueButtontext: return COLOR_BTNTEXT; - case CSSValueCaptiontext: return COLOR_CAPTIONTEXT; - case CSSValueGraytext: return COLOR_GRAYTEXT; - case CSSValueHighlight: return COLOR_HIGHLIGHT; - case CSSValueHighlighttext: return COLOR_HIGHLIGHTTEXT; - case CSSValueInactiveborder: return COLOR_INACTIVEBORDER; - case CSSValueInactivecaption: return COLOR_INACTIVECAPTION; - case CSSValueInactivecaptiontext: return COLOR_INACTIVECAPTIONTEXT; - case CSSValueInfobackground: return COLOR_INFOBK; - case CSSValueInfotext: return COLOR_INFOTEXT; - case CSSValueMenu: return COLOR_MENU; - case CSSValueMenutext: return COLOR_MENUTEXT; - case CSSValueScrollbar: return COLOR_SCROLLBAR; - case CSSValueThreeddarkshadow: return COLOR_3DDKSHADOW; - case CSSValueThreedface: return COLOR_3DFACE; - case CSSValueThreedhighlight: return COLOR_3DHIGHLIGHT; - case CSSValueThreedlightshadow: return COLOR_3DLIGHT; - case CSSValueThreedshadow: return COLOR_3DSHADOW; - case CSSValueWindow: return COLOR_WINDOW; - case CSSValueWindowframe: return COLOR_WINDOWFRAME; - case CSSValueWindowtext: return COLOR_WINDOWTEXT; - default: return -1; // Unsupported CSSValue - } -} - -Color RenderThemeChromiumWin::systemColor(CSSValueID cssValueId) const -{ - int sysColorIndex = cssValueIdToSysColorIndex(cssValueId); - if (isRunningLayoutTest() || (sysColorIndex == -1)) - return RenderTheme::systemColor(cssValueId); - - COLORREF color = GetSysColor(sysColorIndex); - return Color(GetRValue(color), GetGValue(color), GetBValue(color)); -} - -IntSize RenderThemeChromiumWin::sliderTickSize() const -{ - return IntSize(1, 3); -} - -int RenderThemeChromiumWin::sliderTickOffsetFromTrackCenter() const -{ - return 11; -} - -void RenderThemeChromiumWin::adjustSliderThumbSize(RenderStyle* style, Element* element) const -{ - // These sizes match what WinXP draws for various menus. - const int sliderThumbAlongAxis = 11; - const int sliderThumbAcrossAxis = 21; - if (style->appearance() == SliderThumbHorizontalPart) { - style->setWidth(Length(sliderThumbAlongAxis, Fixed)); - style->setHeight(Length(sliderThumbAcrossAxis, Fixed)); - } else if (style->appearance() == SliderThumbVerticalPart) { - style->setWidth(Length(sliderThumbAcrossAxis, Fixed)); - style->setHeight(Length(sliderThumbAlongAxis, Fixed)); - } else - RenderThemeChromiumSkia::adjustSliderThumbSize(style, element); -} - -bool RenderThemeChromiumWin::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r) -{ - return paintButton(o, i, r); -} -bool RenderThemeChromiumWin::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r) -{ - return paintButton(o, i, r); -} - -bool RenderThemeChromiumWin::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r) -{ - const ThemeData& themeData = getThemeData(o); - - ThemePainter painter(i.context, r); - blink::WebCanvas* canvas = painter.context()->canvas(); - blink::Platform::current()->themeEngine()->paintButton(canvas, themeData.m_part, themeData.m_state, themeData.m_classicState, blink::WebRect(painter.drawRect())); - return false; -} - -bool RenderThemeChromiumWin::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r) -{ - return paintTextFieldInternal(o, i, r, true); -} - -bool RenderThemeChromiumWin::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& r) -{ - const ThemeData& themeData = getThemeData(o); - - ThemePainter painter(i.context, r); - blink::WebCanvas* canvas = painter.context()->canvas(); - blink::Platform::current()->themeEngine()->paintTrackbar(canvas, themeData.m_part, themeData.m_state, themeData.m_classicState, blink::WebRect(painter.drawRect())); - - paintSliderTicks(o, i, r); - - return false; -} - -bool RenderThemeChromiumWin::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& r) -{ - const ThemeData& themeData = getThemeData(o); - - ThemePainter painter(i.context, r); - blink::WebCanvas* canvas = painter.context()->canvas(); - blink::Platform::current()->themeEngine()->paintTrackbar(canvas, themeData.m_part, themeData.m_state, themeData.m_classicState, blink::WebRect(painter.drawRect())); - - return false; -} - -static int menuListButtonWidth() -{ - static int width = isRunningLayoutTest() ? kStandardMenuListButtonWidth : - IntSize(blink::Platform::current()->themeEngine()->getSize(SBP_ARROWBTN)).width(); - return width; -} - -// Used to paint unstyled menulists (i.e. with the default border) -bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r) -{ - if (!o->isBox()) - return false; - - const RenderBox* box = toRenderBox(o); - int borderRight = box->borderRight(); - int borderLeft = box->borderLeft(); - int borderTop = box->borderTop(); - int borderBottom = box->borderBottom(); - - // If all the borders are 0, then tell skia not to paint the border on the - // textfield. FIXME: http://b/1210017 Figure out how to get Windows to not - // draw individual borders and then pass that to skia so we can avoid - // drawing any borders that are set to 0. For non-zero borders, we draw the - // border, but webkit just draws over it. - bool drawEdges = !(!borderRight && !borderLeft && !borderTop && !borderBottom); - - paintTextFieldInternal(o, i, r, drawEdges); - return paintMenuListButton(o, i, r); -} - -bool RenderThemeChromiumWin::paintMenuListButton(RenderObject* o, const PaintInfo& i, const IntRect& r) -{ - if (!o->isBox()) - return false; - - const RenderBox* box = toRenderBox(o); - // Take padding and border into account. If the MenuList is smaller than - // the size of a button, make sure to shrink it appropriately and not put - // its x position to the left of the menulist. - const int buttonWidth = menuListButtonWidth(); - int spacingLeft = box->borderLeft() + box->paddingLeft(); - int spacingRight = box->borderRight() + box->paddingRight(); - int spacingTop = box->borderTop() + box->paddingTop(); - int spacingBottom = box->borderBottom() + box->paddingBottom(); - - int buttonX; - if (r.maxX() - r.x() < buttonWidth) - buttonX = r.x(); - else - buttonX = o->style()->direction() == LTR ? r.maxX() - spacingRight - buttonWidth : r.x() + spacingLeft; - - // Compute the rectangle of the button in the destination image. - IntRect rect(buttonX, - r.y() + spacingTop, - std::min(buttonWidth, r.maxX() - r.x()), - r.height() - (spacingTop + spacingBottom)); - - // Get the correct theme data for a textfield and paint the menu. - ThemePainter painter(i.context, rect); - blink::WebCanvas* canvas = painter.context()->canvas(); - blink::Platform::current()->themeEngine()->paintMenuList(canvas, CP_DROPDOWNBUTTON, determineState(o), determineClassicState(o), blink::WebRect(painter.drawRect())); - return false; -} - -double RenderThemeChromiumWin::caretBlinkIntervalInternal() const -{ - // This involves a system call, so we cache the result. - static double blinkInterval = querySystemBlinkInterval(RenderTheme::caretBlinkInterval()); - return blinkInterval; -} - -unsigned RenderThemeChromiumWin::determineState(RenderObject* o, ControlSubPart subPart) -{ - unsigned result = TS_NORMAL; - ControlPart appearance = o->style()->appearance(); - if (!isEnabled(o)) - result = TS_DISABLED; - else if (isReadOnlyControl(o)) - result = (appearance == TextFieldPart || appearance == TextAreaPart || appearance == SearchFieldPart) ? ETS_READONLY : TS_DISABLED; - // Active overrides hover and focused. - else if (isPressed(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartPressed(o)) - result = TS_PRESSED; - else if (supportsFocus(appearance) && isFocused(o)) - result = ETS_FOCUSED; - else if (isHovered(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartHovered(o)) - result = TS_HOT; - - // CBS_UNCHECKED*: 1-4 - // CBS_CHECKED*: 5-8 - // CBS_MIXED*: 9-12 - if (isIndeterminate(o)) - result += 8; - else if (isChecked(o)) - result += 4; - return result; -} - -unsigned RenderThemeChromiumWin::determineSliderThumbState(RenderObject* o) -{ - unsigned result = TUS_NORMAL; - if (!isEnabled(o)) - result = TUS_DISABLED; - else if (supportsFocus(o->style()->appearance()) && isFocused(o)) - result = TUS_FOCUSED; - else if (isPressed(o)) - result = TUS_PRESSED; - else if (isHovered(o)) - result = TUS_HOT; - return result; -} - -unsigned RenderThemeChromiumWin::determineClassicState(RenderObject* o, ControlSubPart subPart) -{ - unsigned result = 0; - - ControlPart part = o->style()->appearance(); - - // Sliders are always in the normal state. - if (part == SliderHorizontalPart || part == SliderVerticalPart) - return result; - - // So are readonly text fields. - if (isReadOnlyControl(o) && (part == TextFieldPart || part == TextAreaPart || part == SearchFieldPart)) - return result; - - if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) { - if (!isEnabled(o)) - result = DFCS_INACTIVE; - else if (isPressed(o)) // Active supersedes hover - result = DFCS_PUSHED; - else if (isHovered(o)) - result = DFCS_HOT; - } else { - if (!isEnabled(o) || isReadOnlyControl(o)) - result = DFCS_INACTIVE; - // Active supersedes hover - else if (isPressed(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartPressed(o)) - result = DFCS_PUSHED; - else if (supportsFocus(part) && isFocused(o)) // So does focused - result = 0; - else if (isHovered(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartHovered(o)) - result = DFCS_HOT; - // Classic theme can't represent indeterminate states. Use unchecked appearance. - if (isChecked(o) && !isIndeterminate(o)) - result |= DFCS_CHECKED; - } - return result; -} - -ThemeData RenderThemeChromiumWin::getThemeData(RenderObject* o, ControlSubPart subPart) -{ - ThemeData result; - switch (o->style()->appearance()) { - case CheckboxPart: - result.m_part = BP_CHECKBOX; - result.m_state = determineState(o); - result.m_classicState = DFCS_BUTTONCHECK; - break; - case RadioPart: - result.m_part = BP_RADIOBUTTON; - result.m_state = determineState(o); - result.m_classicState = DFCS_BUTTONRADIO; - break; - case SquareButtonPart: - case PushButtonPart: - case ButtonPart: - result.m_part = BP_PUSHBUTTON; - result.m_state = determineState(o); - result.m_classicState = DFCS_BUTTONPUSH; - break; - case SliderHorizontalPart: - result.m_part = TKP_TRACK; - result.m_state = TRS_NORMAL; - break; - case SliderVerticalPart: - result.m_part = TKP_TRACKVERT; - result.m_state = TRVS_NORMAL; - break; - case SliderThumbHorizontalPart: - result.m_part = TKP_THUMBBOTTOM; - result.m_state = determineSliderThumbState(o); - break; - case SliderThumbVerticalPart: - result.m_part = TKP_THUMBVERT; - result.m_state = determineSliderThumbState(o); - break; - case ListboxPart: - case MenulistPart: - case MenulistButtonPart: - case SearchFieldPart: - case TextFieldPart: - case TextAreaPart: - result.m_part = EP_EDITTEXT; - result.m_state = determineState(o); - break; - case InnerSpinButtonPart: - result.m_part = subPart == SpinButtonUp ? SPNP_UP : SPNP_DOWN; - result.m_state = determineState(o, subPart); - result.m_classicState = subPart == SpinButtonUp ? DFCS_SCROLLUP : DFCS_SCROLLDOWN; - break; - } - - result.m_classicState |= determineClassicState(o, subPart); - - return result; -} - -bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o, - const PaintInfo& i, - const IntRect& r, - bool drawEdges) -{ - // Fallback to white if the specified color object is invalid. - Color backgroundColor(Color::white); - if (o->style()->visitedDependentColor(CSSPropertyBackgroundColor).isValid()) - backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor); - - // If we have background-image, don't fill the content area to expose the - // parent's background. Also, we shouldn't fill the content area if the - // alpha of the color is 0. The API of Windows GDI ignores the alpha. - // - // Note that we should paint the content area white if we have neither the - // background color nor background image explicitly specified to keep the - // appearance of select element consistent with other browsers. - bool fillContentArea = !o->style()->hasBackgroundImage() && backgroundColor.alpha(); - - if (o->style()->hasBorderRadius()) { - // If the style has rounded borders, setup the context to clip the - // background (themed or filled) appropriately. - // FIXME: make sure we do the right thing if css background-clip is set. - i.context->save(); - i.context->clipRoundedRect(o->style()->getRoundedBorderFor(r)); - } - { - const ThemeData& themeData = getThemeData(o); - ThemePainter painter(i.context, r); - blink::WebCanvas* canvas = painter.context()->canvas(); - blink::Platform::current()->themeEngine()->paintTextField(canvas, themeData.m_part, themeData.m_state, themeData.m_classicState, blink::WebRect(painter.drawRect()), backgroundColor.rgb(), fillContentArea, drawEdges); - // End of block commits the painter before restoring context. - } - if (o->style()->hasBorderRadius()) - i.context->restore(); - return false; -} - -void RenderThemeChromiumWin::adjustInnerSpinButtonStyle(RenderStyle* style, Element*) const -{ - int width = ScrollbarTheme::theme()->scrollbarThickness(); - style->setWidth(Length(width, Fixed)); - style->setMinWidth(Length(width, Fixed)); -} - -bool RenderThemeChromiumWin::paintInnerSpinButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) -{ - IntRect half = rect; - - // Need explicit blocks to avoid to create multiple ThemePainter instances. - { - half.setHeight(rect.height() / 2); - const ThemeData& upThemeData = getThemeData(object, SpinButtonUp); - ThemePainter upPainter(info.context, half); - blink::WebCanvas* canvas = upPainter.context()->canvas(); - blink::Platform::current()->themeEngine()->paintSpinButton(canvas, upThemeData.m_part, upThemeData.m_state, upThemeData.m_classicState, blink::WebRect(upPainter.drawRect())); - } - - { - half.setY(rect.y() + rect.height() / 2); - const ThemeData& downThemeData = getThemeData(object, SpinButtonDown); - ThemePainter downPainter(info.context, half); - blink::WebCanvas* canvas = downPainter.context()->canvas(); - blink::Platform::current()->themeEngine()->paintSpinButton(canvas, downThemeData.m_part, downThemeData.m_state, downThemeData.m_classicState, blink::WebRect(downPainter.drawRect())); - } - return false; -} - -// MSDN says that update intervals for the bar is 30ms. -// http://msdn.microsoft.com/en-us/library/bb760842(v=VS.85).aspx -static const double progressAnimationFrameRate = 0.033; - -double RenderThemeChromiumWin::animationRepeatIntervalForProgressBar(RenderProgress*) const -{ - return progressAnimationFrameRate; -} - -double RenderThemeChromiumWin::animationDurationForProgressBar(RenderProgress* renderProgress) const -{ - // On Chromium Windows port, animationProgress() and associated values aren't used. - // So here we can return arbitrary positive value. - return progressAnimationFrameRate; -} - -bool RenderThemeChromiumWin::paintProgressBar(RenderObject* o, const PaintInfo& i, const IntRect& r) -{ - if (!o->isProgress()) - return true; - - RenderProgress* renderProgress = toRenderProgress(o); - // For indeterminate bar, valueRect is ignored and it is computed by the theme engine - // because the animation is a platform detail and WebKit doesn't need to know how. - IntRect valueRect = renderProgress->isDeterminate() ? determinateProgressValueRectFor(renderProgress, r) : IntRect(0, 0, 0, 0); - double animatedSeconds = renderProgress->animationStartTime() ? WTF::currentTime() - renderProgress->animationStartTime() : 0; - ThemePainter painter(i.context, r); - DirectionFlippingScope scope(o, i, r); - blink::WebCanvas* canvas = painter.context()->canvas(); - blink::Platform::current()->themeEngine()->paintProgressBar(canvas, blink::WebRect(r), blink::WebRect(valueRect), renderProgress->isDeterminate(), animatedSeconds); - return false; -} - -bool RenderThemeChromiumWin::shouldOpenPickerWithF4Key() const -{ - return true; -} - -bool RenderThemeChromiumWin::shouldUseFallbackTheme(RenderStyle* style) const -{ - ControlPart part = style->appearance(); - if (part == CheckboxPart || part == RadioPart) - return style->effectiveZoom() != 1; - return false; -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumWin.h b/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumWin.h deleted file mode 100644 index b44e44bb51e..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderThemeChromiumWin.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * This file is part of the WebKit project. - * - * Copyright (C) 2006 Apple Computer, Inc. - * Copyright (C) 2008, 2009 Google, Inc. - * - * 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 RenderThemeChromiumWin_h -#define RenderThemeChromiumWin_h - -#include "core/rendering/RenderThemeChromiumSkia.h" - -#if WIN32 -typedef void* HANDLE; -typedef struct HINSTANCE__* HINSTANCE; -typedef HINSTANCE HMODULE; -#endif - -namespace WebCore { - -struct ThemeData { - ThemeData() : m_part(0), m_state(0), m_classicState(0) { } - - unsigned m_part; - unsigned m_state; - unsigned m_classicState; -}; - -class RenderThemeChromiumWin : public RenderThemeChromiumSkia { -public: - static PassRefPtr<RenderTheme> create(); - - // A method asking if the theme is able to draw the focus ring. - virtual bool supportsFocusRing(const RenderStyle*) const OVERRIDE; - - // The platform selection color. - virtual Color platformActiveSelectionBackgroundColor() const OVERRIDE; - virtual Color platformInactiveSelectionBackgroundColor() const OVERRIDE; - virtual Color platformActiveSelectionForegroundColor() const OVERRIDE; - virtual Color platformInactiveSelectionForegroundColor() const OVERRIDE; - virtual Color platformActiveTextSearchHighlightColor() const OVERRIDE; - virtual Color platformInactiveTextSearchHighlightColor() const OVERRIDE; - - virtual Color systemColor(CSSValueID) const OVERRIDE; - - virtual IntSize sliderTickSize() const OVERRIDE; - virtual int sliderTickOffsetFromTrackCenter() const OVERRIDE; - virtual void adjustSliderThumbSize(RenderStyle*, Element*) const OVERRIDE; - - // Various paint functions. - virtual bool paintCheckbox(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual bool paintRadio(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual bool paintButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - - // MenuList refers to an unstyled menulist (meaning a menulist without - // background-color or border set) and MenuListButton refers to a styled - // menulist (a menulist with background-color or border set). - virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - - virtual void adjustInnerSpinButtonStyle(RenderStyle*, Element*) const OVERRIDE; - virtual bool paintInnerSpinButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - - virtual double animationRepeatIntervalForProgressBar(RenderProgress*) const OVERRIDE; - virtual double animationDurationForProgressBar(RenderProgress*) const OVERRIDE; - virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; - - virtual bool shouldOpenPickerWithF4Key() const OVERRIDE; - -protected: - virtual double caretBlinkIntervalInternal() const OVERRIDE; - virtual bool shouldUseFallbackTheme(RenderStyle*) const OVERRIDE; - -private: - enum ControlSubPart { - None, - SpinButtonDown, - SpinButtonUp, - }; - - RenderThemeChromiumWin() { } - virtual ~RenderThemeChromiumWin() { } - - unsigned determineState(RenderObject*, ControlSubPart = None); - unsigned determineSliderThumbState(RenderObject*); - unsigned determineClassicState(RenderObject*, ControlSubPart = None); - - ThemeData getThemeData(RenderObject*, ControlSubPart = None); - - bool paintTextFieldInternal(RenderObject*, const PaintInfo&, const IntRect&, bool); -}; - -} // namespace WebCore - -#endif diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTreeAsText.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderTreeAsText.cpp index ccc630e5e81..a450d9773fe 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTreeAsText.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTreeAsText.cpp @@ -26,30 +26,29 @@ #include "config.h" #include "core/rendering/RenderTreeAsText.h" -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/css/StylePropertySet.h" #include "core/dom/Document.h" #include "core/editing/FrameSelection.h" -#include "core/html/HTMLElement.h" -#include "core/frame/Frame.h" #include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" +#include "core/html/HTMLElement.h" #include "core/page/PrintContext.h" -#include "core/rendering/CompositedLayerMapping.h" #include "core/rendering/FlowThreadController.h" #include "core/rendering/InlineTextBox.h" #include "core/rendering/RenderBR.h" #include "core/rendering/RenderDetailsMarker.h" #include "core/rendering/RenderFileUploadControl.h" +#include "core/rendering/RenderFlowThread.h" #include "core/rendering/RenderInline.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderListItem.h" #include "core/rendering/RenderListMarker.h" -#include "core/rendering/RenderNamedFlowThread.h" #include "core/rendering/RenderPart.h" -#include "core/rendering/RenderRegion.h" #include "core/rendering/RenderTableCell.h" #include "core/rendering/RenderView.h" #include "core/rendering/RenderWidget.h" +#include "core/rendering/compositing/CompositedLayerMapping.h" #include "core/rendering/svg/RenderSVGContainer.h" #include "core/rendering/svg/RenderSVGGradientStop.h" #include "core/rendering/svg/RenderSVGImage.h" @@ -115,17 +114,17 @@ static String getTagName(Node* n) static bool isEmptyOrUnstyledAppleStyleSpan(const Node* node) { - if (!node || !node->isHTMLElement() || !node->hasTagName(spanTag)) + if (!isHTMLSpanElement(node)) return false; - const HTMLElement* elem = toHTMLElement(node); - if (elem->getAttribute(classAttr) != "Apple-style-span") + const HTMLElement& elem = toHTMLElement(*node); + if (elem.getAttribute(classAttr) != "Apple-style-span") return false; - if (!node->hasChildNodes()) + if (!elem.hasChildren()) return true; - const StylePropertySet* inlineStyleDecl = elem->inlineStyle(); + const StylePropertySet* inlineStyleDecl = elem.inlineStyle(); return (!inlineStyleDecl || inlineStyleDecl->isEmpty()); } @@ -227,17 +226,17 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, // Do not dump invalid or transparent backgrounds, since that is the default. Color backgroundColor = o.resolveColor(CSSPropertyBackgroundColor); if (o.parent()->resolveColor(CSSPropertyBackgroundColor) != backgroundColor - && backgroundColor.isValid() && backgroundColor.rgb()) + && backgroundColor.rgb()) ts << " [bgcolor=" << backgroundColor.nameForRenderTreeAsText() << "]"; Color textFillColor = o.resolveColor(CSSPropertyWebkitTextFillColor); if (o.parent()->resolveColor(CSSPropertyWebkitTextFillColor) != textFillColor - && textFillColor.isValid() && textFillColor != color && textFillColor.rgb()) + && textFillColor != color && textFillColor.rgb()) ts << " [textFillColor=" << textFillColor.nameForRenderTreeAsText() << "]"; Color textStrokeColor = o.resolveColor(CSSPropertyWebkitTextStrokeColor); if (o.parent()->resolveColor(CSSPropertyWebkitTextStrokeColor) != textStrokeColor - && textStrokeColor.isValid() && textStrokeColor != color && textStrokeColor.rgb()) + && textStrokeColor != color && textStrokeColor.rgb()) ts << " [textStrokeColor=" << textStrokeColor.nameForRenderTreeAsText() << "]"; if (o.parent()->style()->textStrokeWidth() != o.style()->textStrokeWidth() && o.style()->textStrokeWidth() > 0) @@ -475,7 +474,7 @@ void write(TextStream& ts, const RenderObject& o, int indent, RenderAsTextBehavi } } - for (RenderObject* child = o.firstChild(); child; child = child->nextSibling()) { + for (RenderObject* child = o.slowFirstChild(); child; child = child->nextSibling()) { if (child->hasLayer()) continue; write(ts, *child, indent + 1, behavior); @@ -539,10 +538,10 @@ static void write(TextStream& ts, RenderLayer& l, ts << " scrollX " << l.scrollableArea()->scrollXOffset(); if (l.scrollableArea()->scrollYOffset()) ts << " scrollY " << l.scrollableArea()->scrollYOffset(); - if (l.renderBox() && l.renderBox()->pixelSnappedClientWidth() != l.renderBox()->scrollWidth()) - ts << " scrollWidth " << l.renderBox()->scrollWidth(); - if (l.renderBox() && l.renderBox()->pixelSnappedClientHeight() != l.renderBox()->scrollHeight()) - ts << " scrollHeight " << l.renderBox()->scrollHeight(); + if (l.renderBox() && l.renderBox()->pixelSnappedClientWidth() != l.renderBox()->pixelSnappedScrollWidth()) + ts << " scrollWidth " << l.renderBox()->pixelSnappedScrollWidth(); + if (l.renderBox() && l.renderBox()->pixelSnappedClientHeight() != l.renderBox()->pixelSnappedScrollHeight()) + ts << " scrollHeight " << l.renderBox()->pixelSnappedScrollHeight(); } if (paintPhase == LayerPaintPhaseBackground) @@ -550,6 +549,11 @@ static void write(TextStream& ts, RenderLayer& l, else if (paintPhase == LayerPaintPhaseForeground) ts << " layerType: foreground only"; + if (l.blendInfo().childLayerHasBlendMode()) + ts << " isolatesBlending"; + if (l.blendInfo().hasBlendMode()) + ts << " blendMode: " << compositeOperatorName(CompositeSourceOver, l.blendInfo().blendMode()); + if (behavior & RenderAsTextShowCompositedLayers) { if (l.hasCompositedLayerMapping()) { ts << " (composited, bounds=" @@ -558,6 +562,7 @@ static void write(TextStream& ts, RenderLayer& l, << l.compositedLayerMapping()->mainGraphicsLayer()->drawsContent() << ", paints into ancestor=" << l.compositedLayerMapping()->paintsIntoCompositedAncestor() + << (l.shouldIsolateCompositedDescendants() ? ", isolatesCompositedBlending" : "") << ")"; } } @@ -568,91 +573,6 @@ static void write(TextStream& ts, RenderLayer& l, write(ts, *l.renderer(), indent + 1, behavior); } -static void writeRenderRegionList(const RenderRegionList& flowThreadRegionList, TextStream& ts, int indent) -{ - for (RenderRegionList::const_iterator itRR = flowThreadRegionList.begin(); itRR != flowThreadRegionList.end(); ++itRR) { - const RenderRegion* renderRegion = *itRR; - - writeIndent(ts, indent); - ts << renderRegion->renderName(); - - Node* generatingNodeForRegion = renderRegion->generatingNodeForRegion(); - if (generatingNodeForRegion) { - if (renderRegion->hasCustomRegionStyle()) - ts << " region style: 1"; - if (renderRegion->hasAutoLogicalHeight()) - ts << " hasAutoLogicalHeight"; - - bool isRenderNamedFlowFragment = renderRegion->isRenderNamedFlowFragment(); - if (isRenderNamedFlowFragment) - ts << " (anonymous child of"; - - StringBuilder tagName; - tagName.append(generatingNodeForRegion->nodeName()); - - Node* nodeForRegion = renderRegion->nodeForRegion(); - if (nodeForRegion->isPseudoElement()) { - if (nodeForRegion->isBeforePseudoElement()) - tagName.append("::before"); - else if (nodeForRegion->isAfterPseudoElement()) - tagName.append("::after"); - } - - ts << " {" << tagName.toString() << "}"; - - if (generatingNodeForRegion->isElementNode() && generatingNodeForRegion->hasID()) { - Element* element = toElement(generatingNodeForRegion); - ts << " #" << element->idForStyleResolution(); - } - - if (isRenderNamedFlowFragment) - ts << ")"; - } - - if (!renderRegion->isValid()) - ts << " invalid"; - - ts << "\n"; - } -} - -static void writeRenderNamedFlowThreads(TextStream& ts, RenderView* renderView, const RenderLayer* rootLayer, - const LayoutRect& paintRect, int indent, RenderAsTextBehavior behavior) -{ - if (!renderView->hasRenderNamedFlowThreads()) - return; - - const RenderNamedFlowThreadList* list = renderView->flowThreadController()->renderNamedFlowThreadList(); - - writeIndent(ts, indent); - ts << "Named flows\n"; - - for (RenderNamedFlowThreadList::const_iterator iter = list->begin(); iter != list->end(); ++iter) { - const RenderNamedFlowThread* renderFlowThread = *iter; - - writeIndent(ts, indent + 1); - ts << "Named flow '" << renderFlowThread->flowThreadName() << "'\n"; - - RenderLayer* layer = renderFlowThread->layer(); - RenderTreeAsText::writeLayers(ts, rootLayer, layer, paintRect, indent + 2, behavior); - - // Display the valid and invalid render regions attached to this flow thread. - const RenderRegionList& validRegionsList = renderFlowThread->renderRegionList(); - if (!validRegionsList.isEmpty()) { - writeIndent(ts, indent + 2); - ts << "Regions for named flow '" << renderFlowThread->flowThreadName() << "'\n"; - writeRenderRegionList(validRegionsList, ts, indent + 3); - } - - const RenderRegionList& invalidRegionsList = renderFlowThread->invalidRenderRegionList(); - if (!invalidRegionsList.isEmpty()) { - writeIndent(ts, indent + 2); - ts << "Invalid regions for named flow '" << renderFlowThread->flowThreadName() << "'\n"; - writeRenderRegionList(invalidRegionsList, ts, indent + 3); - } - } -} - void RenderTreeAsText::writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLayer* layer, const LayoutRect& paintRect, int indent, RenderAsTextBehavior behavior) { @@ -667,7 +587,7 @@ void RenderTreeAsText::writeLayers(TextStream& ts, const RenderLayer* rootLayer, // Calculate the clip rects we should use. LayoutRect layerBounds; ClipRect damageRect, clipRectToApply, outlineRect; - layer->calculateRects(ClipRectsContext(rootLayer, 0, TemporaryClipRects), paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect); + layer->clipper().calculateRects(ClipRectsContext(rootLayer, TemporaryClipRects), paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect); // Ensure our lists are up-to-date. layer->stackingNode()->updateLayerListsIfNeeded(); @@ -714,13 +634,6 @@ void RenderTreeAsText::writeLayers(TextStream& ts, const RenderLayer* rootLayer, for (unsigned i = 0; i != posList->size(); ++i) writeLayers(ts, rootLayer, posList->at(i)->layer(), paintDirtyRect, currIndent, behavior); } - - // Altough the RenderFlowThread requires a layer, it is not collected by its parent, - // so we have to treat it as a special case. - if (layer->renderer()->isRenderView()) { - RenderView* renderView = toRenderView(layer->renderer()); - writeRenderNamedFlowThreads(ts, renderView, rootLayer, paintDirtyRect, indent, behavior); - } } static String nodePosition(Node* node) @@ -764,7 +677,7 @@ static void writeSelection(TextStream& ts, const RenderObject* o) return; Document* doc = toDocument(n); - Frame* frame = doc->frame(); + LocalFrame* frame = doc->frame(); if (!frame) return; @@ -791,7 +704,7 @@ static String externalRepresentation(RenderBox* renderer, RenderAsTextBehavior b return ts.release(); } -String externalRepresentation(Frame* frame, RenderAsTextBehavior behavior) +String externalRepresentation(LocalFrame* frame, RenderAsTextBehavior behavior) { if (!(behavior & RenderAsTextDontUpdateLayout)) frame->document()->updateLayout(); @@ -802,7 +715,7 @@ String externalRepresentation(Frame* frame, RenderAsTextBehavior behavior) PrintContext printContext(frame); if (behavior & RenderAsTextPrintingMode) - printContext.begin(toRenderBox(renderer)->width()); + printContext.begin(toRenderBox(renderer)->width().toFloat()); return externalRepresentation(toRenderBox(renderer), behavior); } @@ -823,7 +736,7 @@ String externalRepresentation(Element* element, RenderAsTextBehavior behavior) static void writeCounterValuesFromChildren(TextStream& stream, RenderObject* parent, bool& isFirstCounter) { - for (RenderObject* child = parent->firstChild(); child; child = child->nextSibling()) { + for (RenderObject* child = parent->slowFirstChild(); child; child = child->nextSibling()) { if (child->isCounter()) { if (!isFirstCounter) stream << " "; @@ -837,7 +750,7 @@ static void writeCounterValuesFromChildren(TextStream& stream, RenderObject* par String counterValueForElement(Element* element) { // Make sure the element is not freed during the layout. - RefPtr<Element> elementRef(element); + RefPtrWillBeRawPtr<Element> protector(element); element->document().updateLayout(); TextStream stream; bool isFirstCounter = true; @@ -852,7 +765,7 @@ String counterValueForElement(Element* element) String markerTextForListItem(Element* element) { // Make sure the element is not freed during the layout. - RefPtr<Element> elementRef(element); + RefPtrWillBeRawPtr<Element> protector(element); element->document().updateLayout(); RenderObject* renderer = element->renderer(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderTreeAsText.h b/chromium/third_party/WebKit/Source/core/rendering/RenderTreeAsText.h index 63c900ca947..aa66a867604 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderTreeAsText.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderTreeAsText.h @@ -32,7 +32,7 @@ namespace WebCore { class Element; -class Frame; +class LocalFrame; class LayoutRect; class RenderLayer; class RenderObject; @@ -52,7 +52,7 @@ enum RenderAsTextBehaviorFlags { typedef unsigned RenderAsTextBehavior; // You don't need pageWidthInPixels if you don't specify RenderAsTextInPrintingMode. -String externalRepresentation(Frame*, RenderAsTextBehavior = RenderAsTextBehaviorNormal); +String externalRepresentation(LocalFrame*, RenderAsTextBehavior = RenderAsTextBehaviorNormal); String externalRepresentation(Element*, RenderAsTextBehavior = RenderAsTextBehaviorNormal); void write(TextStream&, const RenderObject&, int indent = 0, RenderAsTextBehavior = RenderAsTextBehaviorNormal); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderVTTCue.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderVTTCue.cpp index 4507321ee6f..349e98ad698 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderVTTCue.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderVTTCue.cpp @@ -27,7 +27,6 @@ #include "core/rendering/RenderVTTCue.h" #include "core/html/track/vtt/VTTCue.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/RenderView.h" namespace WebCore { @@ -40,7 +39,6 @@ RenderVTTCue::RenderVTTCue(VTTCueBox* element) void RenderVTTCue::layout() { - LayoutRectRecorder recorder(*this); RenderBlockFlow::layout(); // If WebVTT Regions are used, the regular WebVTT layout algorithm is no @@ -50,14 +48,12 @@ void RenderVTTCue::layout() if (!m_cue->regionId().isEmpty()) return; - LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode()); + LayoutState state(*this, locationOffset()); if (m_cue->snapToLines()) repositionCueSnapToLinesSet(); else repositionCueSnapToLinesNotSet(); - - statePusher.pop(); } bool RenderVTTCue::findFirstLineBox(InlineFlowBox*& firstLineBox) @@ -127,7 +123,8 @@ void RenderVTTCue::placeBoxInDefaultPosition(LayoutUnit position, bool& switched // 9. Default: Remember the position of all the boxes in boxes as their // default position. - m_fallbackPosition = FloatPoint(x(), y()); + // FIXME: Why the direct conversion between float and LayoutUnit? crbug.com/350474 + m_fallbackPosition = FloatPoint(location()); // 10. Let switched be false. switched = false; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderVTTCue.h b/chromium/third_party/WebKit/Source/core/rendering/RenderVTTCue.h index d357b24cc3a..953ff82f4b0 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderVTTCue.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderVTTCue.h @@ -41,7 +41,6 @@ public: private: virtual void layout() OVERRIDE; - virtual bool supportsPartialLayout() const OVERRIDE { return false; } bool isOutside() const; bool isOverlapping() const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderVideo.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderVideo.cpp index b498f90186a..902641ddd06 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderVideo.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderVideo.cpp @@ -27,13 +27,11 @@ #include "core/rendering/RenderVideo.h" -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/dom/Document.h" -#include "core/html/HTMLVideoElement.h" -#include "core/frame/Frame.h" #include "core/frame/FrameView.h" -#include "core/page/Page.h" -#include "core/rendering/LayoutRectRecorder.h" +#include "core/frame/LocalFrame.h" +#include "core/html/HTMLVideoElement.h" #include "core/rendering/PaintInfo.h" #include "core/rendering/RenderFullScreen.h" #include "platform/graphics/media/MediaPlayer.h" @@ -83,7 +81,7 @@ void RenderVideo::updateIntrinsicSize() setIntrinsicSize(size); setPreferredLogicalWidthsDirty(); - setNeedsLayout(); + setNeedsLayoutAndFullPaintInvalidation(); } LayoutSize RenderVideo::calculateIntrinsicSize() @@ -99,9 +97,9 @@ LayoutSize RenderVideo::calculateIntrinsicSize() // The intrinsic height of a video element's playback area is the intrinsic height // of the video resource, if that is available; otherwise it is the intrinsic // height of the poster frame, if that is available; otherwise it is 150 CSS pixels. - MediaPlayer* player = mediaElement()->player(); - if (player && video->readyState() >= HTMLVideoElement::HAVE_METADATA) { - LayoutSize size = player->naturalSize(); + blink::WebMediaPlayer* webMediaPlayer = mediaElement()->webMediaPlayer(); + if (webMediaPlayer && video->readyState() >= HTMLVideoElement::HAVE_METADATA) { + IntSize size = webMediaPlayer->naturalSize(); if (!size.isEmpty()) return size; } @@ -186,14 +184,12 @@ bool RenderVideo::acceleratedRenderingInUse() void RenderVideo::layout() { - LayoutRectRecorder recorder(*this); updatePlayer(); RenderMedia::layout(); } HTMLVideoElement* RenderVideo::videoElement() const { - ASSERT(isHTMLVideoElement(node())); return toHTMLVideoElement(node()); } @@ -214,7 +210,7 @@ void RenderVideo::updatePlayer() if (!videoElement()->isActive()) return; - contentChanged(VideoChanged); + videoElement()->setNeedsCompositingUpdate(); } LayoutUnit RenderVideo::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const @@ -278,4 +274,18 @@ LayoutUnit RenderVideo::offsetHeight() const return RenderMedia::offsetHeight(); } +CompositingReasons RenderVideo::additionalCompositingReasons(CompositingTriggerFlags triggers) const +{ + if (RuntimeEnabledFeatures::overlayFullscreenVideoEnabled()) { + HTMLMediaElement* media = toHTMLMediaElement(node()); + if (media->isFullscreen()) + return CompositingReasonVideo; + } + + if ((triggers & VideoTrigger) && shouldDisplayVideo() && supportsAcceleratedRendering()) + return CompositingReasonVideo; + + return CompositingReasonNone; +} + } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderVideo.h b/chromium/third_party/WebKit/Source/core/rendering/RenderVideo.h index 40a400d9075..405f99cddee 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderVideo.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderVideo.h @@ -30,7 +30,6 @@ namespace WebCore { -class HTMLMediaElement; class HTMLVideoElement; class RenderVideo FINAL : public RenderMedia { @@ -44,35 +43,36 @@ public: bool supportsAcceleratedRendering() const; - virtual bool shouldDisplayVideo() const; + bool shouldDisplayVideo() const; private: - virtual void updateFromElement(); + virtual void updateFromElement() OVERRIDE; inline HTMLVideoElement* videoElement() const; - virtual void intrinsicSizeChanged(); + virtual void intrinsicSizeChanged() OVERRIDE; LayoutSize calculateIntrinsicSize(); void updateIntrinsicSize(); - virtual void imageChanged(WrappedImagePtr, const IntRect*); + virtual void imageChanged(WrappedImagePtr, const IntRect*) OVERRIDE; - virtual const char* renderName() const { return "RenderVideo"; } + virtual const char* renderName() const OVERRIDE { return "RenderVideo"; } - virtual bool requiresLayer() const { return true; } - virtual bool isVideo() const { return true; } + virtual bool isVideo() const OVERRIDE { return true; } - virtual void paintReplaced(PaintInfo&, const LayoutPoint&); + virtual void paintReplaced(PaintInfo&, const LayoutPoint&) OVERRIDE; - virtual void layout(); + virtual void layout() OVERRIDE; virtual LayoutUnit computeReplacedLogicalWidth(ShouldComputePreferred = ComputeActual) const OVERRIDE; - virtual LayoutUnit computeReplacedLogicalHeight() const; + virtual LayoutUnit computeReplacedLogicalHeight() const OVERRIDE; virtual LayoutUnit minimumReplacedHeight() const OVERRIDE; - virtual LayoutUnit offsetLeft() const; - virtual LayoutUnit offsetTop() const; - virtual LayoutUnit offsetWidth() const; - virtual LayoutUnit offsetHeight() const; + virtual LayoutUnit offsetLeft() const OVERRIDE; + virtual LayoutUnit offsetTop() const OVERRIDE; + virtual LayoutUnit offsetWidth() const OVERRIDE; + virtual LayoutUnit offsetHeight() const OVERRIDE; + + virtual CompositingReasons additionalCompositingReasons(CompositingTriggerFlags) const OVERRIDE; void updatePlayer(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderView.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderView.cpp index 05955691af5..8aa9ddacbd3 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderView.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderView.cpp @@ -21,31 +21,29 @@ #include "config.h" #include "core/rendering/RenderView.h" -#include "RuntimeEnabledFeatures.h" #include "core/dom/Document.h" #include "core/dom/Element.h" +#include "core/frame/LocalFrame.h" #include "core/html/HTMLDialogElement.h" #include "core/html/HTMLFrameOwnerElement.h" #include "core/html/HTMLIFrameElement.h" -#include "core/frame/Frame.h" #include "core/page/Page.h" #include "core/rendering/ColumnInfo.h" -#include "core/rendering/CompositedLayerMapping.h" #include "core/rendering/FlowThreadController.h" #include "core/rendering/GraphicsContextAnnotator.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/RenderFlowThread.h" #include "core/rendering/RenderGeometryMap.h" #include "core/rendering/RenderLayer.h" -#include "core/rendering/RenderLayerCompositor.h" #include "core/rendering/RenderSelectionInfo.h" -#include "core/rendering/RenderWidget.h" +#include "core/rendering/compositing/CompositedLayerMapping.h" +#include "core/rendering/compositing/RenderLayerCompositor.h" #include "core/svg/SVGDocumentExtensions.h" +#include "platform/RuntimeEnabledFeatures.h" +#include "platform/TraceEvent.h" #include "platform/geometry/FloatQuad.h" #include "platform/geometry/TransformState.h" #include "platform/graphics/GraphicsContext.h" -#include "platform/graphics/filters/custom/CustomFilterGlobalContext.h" namespace WebCore { @@ -56,11 +54,9 @@ RenderView::RenderView(Document* document) , m_selectionEnd(0) , m_selectionStartPos(-1) , m_selectionEndPos(-1) - , m_maximalOutlineSize(0) , m_pageLogicalHeight(0) , m_pageLogicalHeightChanged(false) , m_layoutState(0) - , m_layoutStateDisableCount(0) , m_renderQuoteHead(0) , m_renderCounterCount(0) { @@ -86,6 +82,8 @@ bool RenderView::hitTest(const HitTestRequest& request, HitTestResult& result) bool RenderView::hitTest(const HitTestRequest& request, const HitTestLocation& location, HitTestResult& result) { + TRACE_EVENT0("blink", "RenderView::hitTest"); + // We have to recursively update layout/style here because otherwise, when the hit test recurses // into a child document, it could trigger a layout on the parent document, which can destroy RenderLayers // that are higher up in the call stack, leading to crashes. @@ -111,7 +109,7 @@ LayoutUnit RenderView::availableLogicalHeight(AvailableLogicalHeightType heightT // If we have columns, then the available logical height is reduced to the column height. if (hasColumns()) return columnInfo()->columnHeight(); - return RenderBlock::availableLogicalHeight(heightType); + return RenderBlockFlow::availableLogicalHeight(heightType); } bool RenderView::isChildAllowed(RenderObject* child, RenderStyle*) const @@ -119,8 +117,9 @@ bool RenderView::isChildAllowed(RenderObject* child, RenderStyle*) const return child->isBox(); } -static bool dialogNeedsCentering(const RenderStyle* style) +static bool canCenterDialog(const RenderStyle* style) { + // FIXME: We must center for FixedPosition as well. return style->position() == AbsolutePosition && style->hasAutoTopAndBottom(); } @@ -130,18 +129,19 @@ void RenderView::positionDialog(RenderBox* box) if (dialog->centeringMode() == HTMLDialogElement::NotCentered) return; if (dialog->centeringMode() == HTMLDialogElement::Centered) { - if (dialogNeedsCentering(box->style())) + if (canCenterDialog(box->style())) box->setY(dialog->centeredPosition()); return; } - if (!dialogNeedsCentering(box->style())) { + ASSERT(dialog->centeringMode() == HTMLDialogElement::NeedsCentering); + if (!canCenterDialog(box->style())) { dialog->setNotCentered(); return; } FrameView* frameView = document().view(); int scrollTop = frameView->scrollOffset().height(); - int visibleHeight = frameView->visibleContentRect(ScrollableArea::IncludeScrollbars).height(); + int visibleHeight = frameView->visibleContentRect(IncludeScrollbars).height(); LayoutUnit top = scrollTop; if (box->height() < visibleHeight) top += (visibleHeight - box->height()) / 2; @@ -157,146 +157,68 @@ void RenderView::positionDialogs() TrackedRendererListHashSet::iterator end = positionedDescendants->end(); for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) { RenderBox* box = *it; - if (box->node() && box->node()->hasTagName(HTMLNames::dialogTag)) + if (isHTMLDialogElement(box->node())) positionDialog(box); } } -void RenderView::layoutContent(const LayoutState& state) +void RenderView::layoutContent() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); - RenderBlock::layout(); + RenderBlockFlow::layout(); if (RuntimeEnabledFeatures::dialogElementEnabled()) positionDialogs(); - if (m_frameView->partialLayout().isStopping()) - return; - - if (hasRenderNamedFlowThreads()) - flowThreadController()->layoutRenderNamedFlowThreads(); - #ifndef NDEBUG - checkLayoutState(state); + checkLayoutState(); #endif } #ifndef NDEBUG -void RenderView::checkLayoutState(const LayoutState& state) +void RenderView::checkLayoutState() { - ASSERT(layoutDeltaMatches(LayoutSize())); - ASSERT(!m_layoutStateDisableCount); - ASSERT(m_layoutState == &state); + if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) { + ASSERT(layoutDeltaMatches(LayoutSize())); + } + ASSERT(!m_layoutState->next()); } #endif -static RenderBox* enclosingSeamlessRenderer(const Document& doc) +bool RenderView::shouldDoFullRepaintForNextLayout() const { - Element* ownerElement = doc.seamlessParentIFrame(); - if (!ownerElement) - return 0; - return ownerElement->renderBox(); -} - -void RenderView::addChild(RenderObject* newChild, RenderObject* beforeChild) -{ - // Seamless iframes are considered part of an enclosing render flow thread from the parent document. This is necessary for them to look - // up regions in the parent document during layout. - if (newChild && !newChild->isRenderFlowThread()) { - RenderBox* seamlessBox = enclosingSeamlessRenderer(document()); - if (seamlessBox && seamlessBox->flowThreadContainingBlock()) - newChild->setFlowThreadState(seamlessBox->flowThreadState()); - } - RenderBlock::addChild(newChild, beforeChild); -} + // It's hard to predict here which of full repaint or per-descendant repaint costs less. + // For vertical writing mode or width change it's more likely that per-descendant repaint + // eventually turns out to be full repaint but with the cost to handle more layout states + // and discrete repaint rects, so marking full repaint here is more likely to cost less. + // Otherwise, per-descendant repaint is more likely to avoid unnecessary full repaints. -bool RenderView::initializeLayoutState(LayoutState& state) -{ - bool isSeamlessAncestorInFlowThread = false; - - // FIXME: May be better to push a clip and avoid issuing offscreen repaints. - state.m_clipped = false; - - // Check the writing mode of the seamless ancestor. It has to match our document's writing mode, or we won't inherit any - // pagination information. - RenderBox* seamlessAncestor = enclosingSeamlessRenderer(document()); - LayoutState* seamlessLayoutState = seamlessAncestor ? seamlessAncestor->view()->layoutState() : 0; - bool shouldInheritPagination = seamlessLayoutState && !m_pageLogicalHeight && seamlessAncestor->style()->writingMode() == style()->writingMode(); - - state.m_pageLogicalHeight = shouldInheritPagination ? seamlessLayoutState->m_pageLogicalHeight : m_pageLogicalHeight; - state.m_pageLogicalHeightChanged = shouldInheritPagination ? seamlessLayoutState->m_pageLogicalHeightChanged : m_pageLogicalHeightChanged; - state.m_isPaginated = state.m_pageLogicalHeight; - if (state.m_isPaginated && shouldInheritPagination) { - // Set up the correct pagination offset. We can use a negative offset in order to push the top of the RenderView into its correct place - // on a page. We can take the iframe's offset from the logical top of the first page and make the negative into the pagination offset within the child - // view. - bool isFlipped = seamlessAncestor->style()->isFlippedBlocksWritingMode(); - LayoutSize layoutOffset = seamlessLayoutState->layoutOffset(); - LayoutSize iFrameOffset(layoutOffset.width() + seamlessAncestor->x() + (!isFlipped ? seamlessAncestor->borderLeft() + seamlessAncestor->paddingLeft() : - seamlessAncestor->borderRight() + seamlessAncestor->paddingRight()), - layoutOffset.height() + seamlessAncestor->y() + (!isFlipped ? seamlessAncestor->borderTop() + seamlessAncestor->paddingTop() : - seamlessAncestor->borderBottom() + seamlessAncestor->paddingBottom())); - - LayoutSize offsetDelta = seamlessLayoutState->m_pageOffset - iFrameOffset; - state.m_pageOffset = offsetDelta; - - // Set the current render flow thread to point to our ancestor. This will allow the seamless document to locate the correct - // regions when doing a layout. - if (seamlessAncestor->flowThreadContainingBlock()) { - flowThreadController()->setCurrentRenderFlowThread(seamlessAncestor->view()->flowThreadController()->currentRenderFlowThread()); - isSeamlessAncestorInFlowThread = true; + if (shouldUsePrintingLayout()) + return true; + + if (!style()->isHorizontalWritingMode() || width() != viewWidth()) + return true; + + if (height() != viewHeight()) { + // FIXME: Disable optimization to fix crbug.com/390378 for the branch. + return true; +#if 0 + if (RenderObject* backgroundRenderer = this->backgroundRenderer()) { + // When background-attachment is 'fixed', we treat the viewport (instead of the 'root' + // i.e. html or body) as the background positioning area, and we should full repaint + // viewport resize if the background image is not composited and needs full repaint on + // background positioning area resize. + if (!m_compositor || !m_compositor->needsFixedRootBackgroundLayer(layer())) { + if (backgroundRenderer->style()->hasFixedBackgroundImage() + && mustInvalidateFillLayersPaintOnHeightChange(*backgroundRenderer->style()->backgroundLayers())) + return true; + } } +#endif } - // FIXME: We need to make line grids and exclusions work with seamless iframes as well here. Basically all layout state information needs - // to propagate here and not just pagination information. - return isSeamlessAncestorInFlowThread; -} - -// The algorithm below assumes this is a full layout. In case there are previously computed values for regions, supplemental steps are taken -// to ensure the results are the same as those obtained from a full layout (i.e. the auto-height regions from all the flows are marked as needing -// layout). -// 1. The flows are laid out from the outer flow to the inner flow. This successfully computes the outer non-auto-height regions size so the -// inner flows have the necessary information to correctly fragment the content. -// 2. The flows are laid out from the inner flow to the outer flow. After an inner flow is laid out it goes into the constrained layout phase -// and marks the auto-height regions they need layout. This means the outer flows will relayout if they depend on regions with auto-height regions -// belonging to inner flows. This step will correctly set the computedAutoHeight for the auto-height regions. It's possible for non-auto-height -// regions to relayout if they depend on auto-height regions. This will invalidate the inner flow threads and mark them as needing layout. -// 3. The last step is to do one last layout if there are pathological dependencies between non-auto-height regions and auto-height regions -// as detected in the previous step. -void RenderView::layoutContentInAutoLogicalHeightRegions(const LayoutState& state) -{ - if (!m_frameView->partialLayout().isStopping()) { - // Disable partial layout for any two-pass layout algorithm. - m_frameView->partialLayout().reset(); - } - - // We need to invalidate all the flows with auto-height regions if one such flow needs layout. - // If none is found we do a layout a check back again afterwards. - if (!flowThreadController()->updateFlowThreadsNeedingLayout()) { - // Do a first layout of the content. In some cases more layouts are not needed (e.g. only flows with non-auto-height regions have changed). - layoutContent(state); - - // If we find no named flow needing a two step layout after the first layout, exit early. - // Otherwise, initiate the two step layout algorithm and recompute all the flows. - if (!flowThreadController()->updateFlowThreadsNeedingTwoStepLayout()) - return; - } - - // Layout to recompute all the named flows with auto-height regions. - layoutContent(state); - - // Propagate the computed auto-height values upwards. - // Non-auto-height regions may invalidate the flow thread because they depended on auto-height regions, but that's ok. - flowThreadController()->updateFlowThreadsIntoConstrainedPhase(); - - // Do one last layout that should update the auto-height regions found in the main flow - // and solve pathological dependencies between regions (e.g. a non-auto-height region depending - // on an auto-height one). - if (needsLayout()) - layoutContent(state); + return false; } void RenderView::layout() @@ -307,7 +229,7 @@ void RenderView::layout() if (shouldUsePrintingLayout()) m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = logicalWidth(); - SubtreeLayoutScope layoutScope(this); + SubtreeLayoutScope layoutScope(*this); // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account. bool relayoutChildren = !shouldUsePrintingLayout() && (!m_frameView || width() != viewWidth() || height() != viewHeight()); @@ -320,45 +242,28 @@ void RenderView::layout() if ((child->isBox() && toRenderBox(child)->hasRelativeLogicalHeight()) || child->style()->logicalHeight().isPercent() || child->style()->logicalMinHeight().isPercent() - || child->style()->logicalMaxHeight().isPercent() - || child->style()->logicalHeight().isViewportPercentage() - || child->style()->logicalMinHeight().isViewportPercentage() - || child->style()->logicalMaxHeight().isViewportPercentage()) + || child->style()->logicalMaxHeight().isPercent()) layoutScope.setChildNeedsLayout(child); } if (document().svgExtensions()) - document().accessSVGExtensions()->invalidateSVGRootsWithRelativeLengthDescendents(&layoutScope); + document().accessSVGExtensions().invalidateSVGRootsWithRelativeLengthDescendents(&layoutScope); } ASSERT(!m_layoutState); if (!needsLayout()) return; - LayoutState state; - bool isSeamlessAncestorInFlowThread = initializeLayoutState(state); + LayoutState rootLayoutState(pageLogicalHeight(), pageLogicalHeightChanged(), *this); m_pageLogicalHeightChanged = false; - m_layoutState = &state; - if (checkTwoPassLayoutForAutoHeightRegions()) - layoutContentInAutoLogicalHeightRegions(state); - else - layoutContent(state); - - if (m_frameView->partialLayout().isStopping()) { - m_layoutState = 0; - return; - } + layoutContent(); #ifndef NDEBUG - checkLayoutState(state); + checkLayoutState(); #endif - m_layoutState = 0; clearNeedsLayout(); - - if (isSeamlessAncestorInFlowThread) - flowThreadController()->setCurrentRenderFlowThread(0); } void RenderView::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const @@ -444,32 +349,6 @@ void RenderView::computeSelfHitTestRects(Vector<LayoutRect>& rects, const Layout rects.append(LayoutRect(LayoutPoint::zero(), frameView()->contentsSize())); } -bool RenderView::requiresColumns(int desiredColumnCount) const -{ - if (m_frameView) - return m_frameView->pagination().mode != Pagination::Unpaginated; - - return RenderBlock::requiresColumns(desiredColumnCount); -} - -void RenderView::calcColumnWidth() -{ - int columnWidth = contentLogicalWidth(); - if (m_frameView && style()->hasInlineColumnAxis()) { - if (int pageLength = m_frameView->pagination().pageLength) - columnWidth = pageLength; - } - setDesiredColumnCountAndWidth(1, columnWidth); -} - -ColumnInfo::PaginationUnit RenderView::paginationUnit() const -{ - if (m_frameView) - return m_frameView->pagination().behavesLikeColumns ? ColumnInfo::Column : ColumnInfo::Page; - - return ColumnInfo::Page; -} - void RenderView::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // If we ever require layout but receive a paint anyway, something has gone horribly wrong. @@ -480,33 +359,42 @@ void RenderView::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this); // This avoids painting garbage between columns if there is a column gap. - if (m_frameView && m_frameView->pagination().mode != Pagination::Unpaginated) + if (m_frameView && style()->isOverflowPaged()) paintInfo.context->fillRect(paintInfo.rect, m_frameView->baseBackgroundColor()); paintObject(paintInfo, paintOffset); } -static inline bool rendererObscuresBackground(RenderObject* rootObject) +static inline bool rendererObscuresBackground(RenderBox* rootBox) { - if (!rootObject) - return false; - - RenderStyle* style = rootObject->style(); + ASSERT(rootBox); + RenderStyle* style = rootBox->style(); if (style->visibility() != VISIBLE || style->opacity() != 1 + || style->hasFilter() || style->hasTransform()) return false; - if (rootObject->compositingState() == PaintsIntoOwnBacking) + if (rootBox->compositingState() == PaintsIntoOwnBacking) return false; - const RenderObject* rootRenderer = rootObject->rendererForRootBackground(); + const RenderObject* rootRenderer = rootBox->rendererForRootBackground(); if (rootRenderer->style()->backgroundClip() == TextFillBox) return false; return true; } +bool RenderView::rootFillsViewportBackground(RenderBox* rootBox) const +{ + ASSERT(rootBox); + // CSS Boxes always fill the viewport background (see paintRootBoxFillLayers) + if (!rootBox->isSVG()) + return true; + + return rootBox->frameRect().contains(frameRect()); +} + void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&) { // Check to see if we are enclosed by a layer that requires complex painting rules. If so, we cannot blit @@ -534,21 +422,13 @@ void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&) if (paintInfo.skipRootBackground()) return; - bool rootFillsViewport = false; - bool rootObscuresBackground = false; + bool shouldPaintBackground = true; Node* documentElement = document().documentElement(); - if (RenderObject* rootRenderer = documentElement ? documentElement->renderer() : 0) { - // The document element's renderer is currently forced to be a block, but may not always be. - RenderBox* rootBox = rootRenderer->isBox() ? toRenderBox(rootRenderer) : 0; - rootFillsViewport = rootBox && !rootBox->x() && !rootBox->y() && rootBox->width() >= width() && rootBox->height() >= height(); - rootObscuresBackground = rendererObscuresBackground(rootRenderer); - } - - Page* page = document().page(); - float pageScaleFactor = page ? page->pageScaleFactor() : 1; + if (RenderBox* rootBox = documentElement ? toRenderBox(documentElement->renderer()) : 0) + shouldPaintBackground = !rootFillsViewportBackground(rootBox) || !rendererObscuresBackground(rootBox); // If painting will entirely fill the view, no need to fill the background. - if (rootFillsViewport && rootObscuresBackground && pageScaleFactor >= 1) + if (!shouldPaintBackground) return; // This code typically only executes if the root element's visibility has been set to hidden, @@ -570,63 +450,64 @@ void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&) } } -bool RenderView::shouldRepaint(const LayoutRect& rect) const +void RenderView::invalidateTreeAfterLayout(const RenderLayerModelObject& paintInvalidationContainer) { - if (document().printing()) - return false; - return m_frameView && !rect.isEmpty(); + ASSERT(RuntimeEnabledFeatures::repaintAfterLayoutEnabled()); + ASSERT(!needsLayout()); + + // We specifically need to repaint the viewRect since other renderers + // short-circuit on full-repaint. + if (doingFullRepaint() && !viewRect().isEmpty()) + repaintViewRectangle(viewRect()); + + LayoutState rootLayoutState(0, false, *this); + RenderBlock::invalidateTreeAfterLayout(paintInvalidationContainer); } -void RenderView::repaintViewRectangle(const LayoutRect& ur) const +void RenderView::repaintViewRectangle(const LayoutRect& repaintRect) const { - if (!shouldRepaint(ur)) + ASSERT(!repaintRect.isEmpty()); + + if (document().printing() || !m_frameView) return; // We always just invalidate the root view, since we could be an iframe that is clipped out // or even invisible. - Element* elt = document().ownerElement(); - if (!elt) - m_frameView->repaintContentRectangle(pixelSnappedIntRect(ur)); - else if (RenderBox* obj = elt->renderBox()) { - LayoutRect vr = viewRect(); - LayoutRect r = intersection(ur, vr); + Element* owner = document().ownerElement(); + if (layer()->compositingState() == PaintsIntoOwnBacking) { + layer()->repainter().setBackingNeedsRepaintInRect(repaintRect); + } else if (!owner) { + m_frameView->contentRectangleForPaintInvalidation(pixelSnappedIntRect(repaintRect)); + } else if (RenderBox* obj = owner->renderBox()) { + LayoutRect viewRectangle = viewRect(); + LayoutRect rectToRepaint = intersection(repaintRect, viewRectangle); // Subtract out the contentsX and contentsY offsets to get our coords within the viewing // rectangle. - r.moveBy(-vr.location()); + rectToRepaint.moveBy(-viewRectangle.location()); // FIXME: Hardcoded offsets here are not good. - r.moveBy(obj->contentBoxRect().location()); - obj->repaintRectangle(r); - } -} - -void RenderView::repaintRectangleInViewAndCompositedLayers(const LayoutRect& ur) -{ - if (!shouldRepaint(ur)) - return; - - repaintViewRectangle(ur); - - if (compositor()->inCompositingMode()) { - IntRect repaintRect = pixelSnappedIntRect(ur); - compositor()->repaintCompositedLayers(&repaintRect); + rectToRepaint.moveBy(obj->contentBoxRect().location()); + obj->invalidatePaintRectangle(rectToRepaint); } } void RenderView::repaintViewAndCompositedLayers() { - repaint(); + paintInvalidationForWholeRenderer(); + + // The only way we know how to hit these ASSERTS below this point is via the Chromium OS login screen. + DisableCompositingQueryAsserts disabler; if (compositor()->inCompositingMode()) compositor()->repaintCompositedLayers(); } -void RenderView::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const +void RenderView::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, 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. - ASSERT_ARG(repaintContainer, !repaintContainer || repaintContainer == this); + ASSERT_ARG(paintInvalidationContainer, !paintInvalidationContainer || paintInvalidationContainer == this); if (document().printing()) return; @@ -640,11 +521,16 @@ void RenderView::computeRectForRepaint(const RenderLayerModelObject* repaintCont rect.setX(viewWidth() - rect.maxX()); } - if (fixed && m_frameView) + if (fixed && m_frameView) { rect.move(m_frameView->scrollOffsetForFixedPosition()); + // If we have a pending scroll, invalidate the previous scroll position. + if (!m_frameView->pendingScrollDelta().isZero()) { + rect.move(-m_frameView->pendingScrollDelta()); + } + } // Apply our transform if we have one (because of full page zooming). - if (!repaintContainer && layer() && layer()->transform()) + if (!paintInvalidationContainer && layer() && layer()->transform()) rect = layer()->transform()->mapRect(rect); } @@ -682,7 +568,7 @@ IntRect RenderView::selectionBounds(bool clipToVisibleContent) const selectedObjects.set(os, adoptPtr(new RenderSelectionInfo(os, clipToVisibleContent))); RenderBlock* cb = os->containingBlock(); while (cb && !cb->isRenderView()) { - OwnPtr<RenderSelectionInfo>& blockInfo = selectedObjects.add(cb, nullptr).iterator->value; + OwnPtr<RenderSelectionInfo>& blockInfo = selectedObjects.add(cb, nullptr).storedValue->value; if (blockInfo) break; blockInfo = adoptPtr(new RenderSelectionInfo(cb, clipToVisibleContent)); @@ -700,7 +586,7 @@ IntRect RenderView::selectionBounds(bool clipToVisibleContent) const RenderSelectionInfo* info = i->value.get(); // RenderSelectionInfo::rect() is in the coordinates of the repaintContainer, so map to page coordinates. LayoutRect currRect = info->rect(); - if (RenderLayerModelObject* repaintContainer = info->repaintContainer()) { + if (const RenderLayerModelObject* repaintContainer = info->repaintContainer()) { FloatQuad absQuad = repaintContainer->localToAbsoluteQuad(FloatRect(currRect)); currRect = absQuad.enclosingBoundingBox(); } @@ -731,19 +617,6 @@ void RenderView::repaintSelection() const } } -// Compositing layer dimensions take outline size into account, so we have to recompute layer -// bounds when it changes. -// FIXME: This is ugly; it would be nice to have a better way to do this. -void RenderView::setMaximalOutlineSize(int o) -{ - if (o != m_maximalOutlineSize) { - m_maximalOutlineSize = o; - - // maximalOutlineSize affects compositing layer dimensions. - compositor()->setCompositingLayersNeedRebuild(); // FIXME: this really just needs to be a geometry update. - } -} - // When exploring the RenderTree looking for the nodes involved in the Selection, sometimes it's // required to change the traversing direction because the "start" position is below the "end" one. static inline RenderObject* getNextOrPrevRenderObjectBasedOnDirection(const RenderObject* o, const RenderObject* stop, bool& continueExploring, bool& exploringBackwards) @@ -810,7 +683,7 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e if (blockRepaintMode == RepaintNewXOROld) { RenderBlock* cb = os->containingBlock(); while (cb && !cb->isRenderView()) { - OwnPtr<RenderBlockSelectionInfo>& blockInfo = oldSelectedBlocks.add(cb, nullptr).iterator->value; + OwnPtr<RenderBlockSelectionInfo>& blockInfo = oldSelectedBlocks.add(cb, nullptr).storedValue->value; if (blockInfo) break; blockInfo = adoptPtr(new RenderBlockSelectionInfo(cb)); @@ -865,7 +738,7 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e newSelectedObjects.set(o, adoptPtr(new RenderSelectionInfo(o, true))); RenderBlock* cb = o->containingBlock(); while (cb && !cb->isRenderView()) { - OwnPtr<RenderBlockSelectionInfo>& blockInfo = newSelectedBlocks.add(cb, nullptr).iterator->value; + OwnPtr<RenderBlockSelectionInfo>& blockInfo = newSelectedBlocks.add(cb, nullptr).storedValue->value; if (blockInfo) break; blockInfo = adoptPtr(new RenderBlockSelectionInfo(cb)); @@ -879,8 +752,6 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e if (!m_frameView || blockRepaintMode == RepaintNothing) return; - FrameView::DeferredRepaintScope deferRepaints(*m_frameView); - // Have any of the old selected objects changed compared to the new selection? for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i) { RenderObject* obj = i->key; @@ -950,57 +821,6 @@ bool RenderView::shouldUsePrintingLayout() const return m_frameView->frame().shouldUsePrintingLayout(); } -size_t RenderView::getRetainedWidgets(Vector<RenderWidget*>& renderWidgets) -{ - size_t size = m_widgets.size(); - - renderWidgets.reserveCapacity(size); - - RenderWidgetSet::const_iterator end = m_widgets.end(); - for (RenderWidgetSet::const_iterator it = m_widgets.begin(); it != end; ++it) { - renderWidgets.uncheckedAppend(*it); - (*it)->ref(); - } - - return size; -} - -void RenderView::releaseWidgets(Vector<RenderWidget*>& renderWidgets) -{ - size_t size = renderWidgets.size(); - - for (size_t i = 0; i < size; ++i) - renderWidgets[i]->deref(); -} - -void RenderView::updateWidgetPositions() -{ - // updateWidgetPosition() can possibly cause layout to be re-entered (via plug-ins running - // scripts in response to NPP_SetWindow, for example), so we need to keep the Widgets - // alive during enumeration. - - Vector<RenderWidget*> renderWidgets; - size_t size = getRetainedWidgets(renderWidgets); - - for (size_t i = 0; i < size; ++i) - renderWidgets[i]->updateWidgetPosition(); - - for (size_t i = 0; i < size; ++i) - renderWidgets[i]->widgetPositionsUpdated(); - - releaseWidgets(renderWidgets); -} - -void RenderView::addWidget(RenderWidget* o) -{ - m_widgets.add(o); -} - -void RenderView::removeWidget(RenderWidget* o) -{ - m_widgets.remove(o); -} - LayoutRect RenderView::viewRect() const { if (shouldUsePrintingLayout()) @@ -1019,12 +839,18 @@ IntRect RenderView::unscaledDocumentRect() const bool RenderView::rootBackgroundIsEntirelyFixed() const { - RenderObject* rootObject = document().documentElement() ? document().documentElement()->renderer() : 0; - if (!rootObject) - return false; + if (RenderObject* backgroundRenderer = this->backgroundRenderer()) + return backgroundRenderer->hasEntirelyFixedBackground(); + return false; +} - RenderObject* rootRenderer = rootObject->rendererForRootBackground(); - return rootRenderer->hasEntirelyFixedBackground(); +RenderObject* RenderView::backgroundRenderer() const +{ + if (Element* documentElement = document().documentElement()) { + if (RenderObject* rootObject = documentElement->renderer()) + return rootObject->rendererForRootBackground(); + } + return 0; } LayoutRect RenderView::backgroundRect(RenderBox* backgroundRenderer) const @@ -1049,7 +875,7 @@ IntRect RenderView::documentRect() const return IntRect(overflowRect); } -int RenderView::viewHeight(ScrollableArea::IncludeScrollbarsInRect scrollbarInclusion) const +int RenderView::viewHeight(IncludeScrollbarsInRect scrollbarInclusion) const { int height = 0; if (!shouldUsePrintingLayout() && m_frameView) @@ -1058,7 +884,7 @@ int RenderView::viewHeight(ScrollableArea::IncludeScrollbarsInRect scrollbarIncl return height; } -int RenderView::viewWidth(ScrollableArea::IncludeScrollbarsInRect scrollbarInclusion) const +int RenderView::viewWidth(IncludeScrollbarsInRect scrollbarInclusion) const { int width = 0; if (!shouldUsePrintingLayout() && m_frameView) @@ -1067,41 +893,21 @@ int RenderView::viewWidth(ScrollableArea::IncludeScrollbarsInRect scrollbarInclu return width; } -int RenderView::viewLogicalHeight(ScrollableArea::IncludeScrollbarsInRect scrollbarInclusion) const -{ - int height = style()->isHorizontalWritingMode() ? viewHeight(scrollbarInclusion) : viewWidth(scrollbarInclusion); - - if (hasColumns() && !style()->hasInlineColumnAxis()) { - if (int pageLength = m_frameView->pagination().pageLength) - height = pageLength; - } - - return height; -} - -float RenderView::zoomFactor() const +int RenderView::viewLogicalHeight() const { - return m_frameView->frame().pageZoomFactor(); + return style()->isHorizontalWritingMode() ? viewHeight(ExcludeScrollbars) : viewWidth(ExcludeScrollbars); } -void RenderView::pushLayoutState(RenderObject* root) +LayoutUnit RenderView::viewLogicalHeightForPercentages() const { - ASSERT(m_layoutStateDisableCount == 0); - ASSERT(m_layoutState == 0); - - pushLayoutStateForCurrentFlowThread(root); - m_layoutState = new LayoutState(root); + if (shouldUsePrintingLayout()) + return pageLogicalHeight(); + return viewLogicalHeight(); } -bool RenderView::shouldDisableLayoutStateForSubtree(RenderObject* renderer) const +float RenderView::zoomFactor() const { - RenderObject* o = renderer; - while (o) { - if (o->hasColumns() || o->hasTransform() || o->hasReflection()) - return true; - o = o->container(); - } - return false; + return m_frameView->frame().pageZoomFactor(); } void RenderView::updateHitTestResult(HitTestResult& result, const LayoutPoint& point) @@ -1124,13 +930,13 @@ void RenderView::updateHitTestResult(HitTestResult& result, const LayoutPoint& p bool RenderView::usesCompositing() const { - return m_compositor && m_compositor->inCompositingMode(); + return m_compositor && m_compositor->staleInCompositingMode(); } RenderLayerCompositor* RenderView::compositor() { if (!m_compositor) - m_compositor = adoptPtr(new RenderLayerCompositor(this)); + m_compositor = adoptPtr(new RenderLayerCompositor(*this)); return m_compositor.get(); } @@ -1141,52 +947,28 @@ void RenderView::setIsInWindow(bool isInWindow) m_compositor->setIsInWindow(isInWindow); } -CustomFilterGlobalContext* RenderView::customFilterGlobalContext() -{ - if (!m_customFilterGlobalContext) - m_customFilterGlobalContext = adoptPtr(new CustomFilterGlobalContext()); - return m_customFilterGlobalContext.get(); -} - -void RenderView::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) -{ - RenderBlock::styleDidChange(diff, oldStyle); - if (hasRenderNamedFlowThreads()) - flowThreadController()->styleDidChange(); -} - -bool RenderView::hasRenderNamedFlowThreads() const -{ - return m_flowThreadController && m_flowThreadController->hasRenderNamedFlowThreads(); -} - -bool RenderView::checkTwoPassLayoutForAutoHeightRegions() const -{ - return hasRenderNamedFlowThreads() && m_flowThreadController->hasFlowThreadsWithAutoLogicalHeightRegions(); -} - FlowThreadController* RenderView::flowThreadController() { if (!m_flowThreadController) - m_flowThreadController = FlowThreadController::create(this); + m_flowThreadController = FlowThreadController::create(); return m_flowThreadController.get(); } -void RenderView::pushLayoutStateForCurrentFlowThread(const RenderObject* object) +void RenderView::pushLayoutState(LayoutState& layoutState) { - if (!m_flowThreadController) - return; - - RenderFlowThread* currentFlowThread = m_flowThreadController->currentRenderFlowThread(); - if (!currentFlowThread) - return; - - currentFlowThread->pushFlowThreadLayoutState(object); + if (m_flowThreadController) { + RenderFlowThread* currentFlowThread = m_flowThreadController->currentRenderFlowThread(); + if (currentFlowThread) + currentFlowThread->pushFlowThreadLayoutState(layoutState.renderer()); + } + m_layoutState = &layoutState; } -void RenderView::popLayoutStateForCurrentFlowThread() +void RenderView::popLayoutState() { + ASSERT(m_layoutState); + m_layoutState = m_layoutState->next(); if (!m_flowThreadController) return; @@ -1207,70 +989,22 @@ IntervalArena* RenderView::intervalArena() bool RenderView::backgroundIsKnownToBeOpaqueInRect(const LayoutRect&) const { // FIXME: Remove this main frame check. Same concept applies to subframes too. - if (!m_frameView || !m_frameView->isMainFrame()) + if (!frame()->isMainFrame()) return false; return m_frameView->hasOpaqueBackground(); } -LayoutUnit RenderView::viewportPercentageWidth(float percentage) const -{ - return viewLogicalWidth(ScrollableArea::IncludeScrollbars) * percentage / 100.f; -} - -LayoutUnit RenderView::viewportPercentageHeight(float percentage) const +double RenderView::layoutViewportWidth() const { - return viewLogicalHeight(ScrollableArea::IncludeScrollbars) * percentage / 100.f; + float scale = m_frameView ? m_frameView->frame().pageZoomFactor() : 1; + return viewWidth(IncludeScrollbars) / scale; } -LayoutUnit RenderView::viewportPercentageMin(float percentage) const +double RenderView::layoutViewportHeight() const { - return std::min(viewLogicalWidth(ScrollableArea::IncludeScrollbars), viewLogicalHeight(ScrollableArea::IncludeScrollbars)) - * percentage / 100.f; -} - -LayoutUnit RenderView::viewportPercentageMax(float percentage) const -{ - return std::max(viewLogicalWidth(ScrollableArea::IncludeScrollbars), viewLogicalHeight(ScrollableArea::IncludeScrollbars)) - * percentage / 100.f; -} - -FragmentationDisabler::FragmentationDisabler(RenderObject* root) -{ - RenderView* renderView = root->view(); - ASSERT(renderView); - - LayoutState* layoutState = renderView->layoutState(); - - m_root = root; - m_fragmenting = layoutState && layoutState->isPaginated(); - m_flowThreadState = m_root->flowThreadState(); -#ifndef NDEBUG - m_layoutState = layoutState; -#endif - - if (layoutState) - layoutState->m_isPaginated = false; - - if (m_flowThreadState != RenderObject::NotInsideFlowThread) - m_root->setFlowThreadStateIncludingDescendants(RenderObject::NotInsideFlowThread); -} - -FragmentationDisabler::~FragmentationDisabler() -{ - RenderView* renderView = m_root->view(); - ASSERT(renderView); - - LayoutState* layoutState = renderView->layoutState(); -#ifndef NDEBUG - ASSERT(m_layoutState == layoutState); -#endif - - if (layoutState) - layoutState->m_isPaginated = m_fragmenting; - - if (m_flowThreadState != RenderObject::NotInsideFlowThread) - m_root->setFlowThreadStateIncludingDescendants(m_flowThreadState); + float scale = m_frameView ? m_frameView->frame().pageZoomFactor() : 1; + return viewHeight(IncludeScrollbars) / scale; } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderView.h b/chromium/third_party/WebKit/Source/core/rendering/RenderView.h index 246db98be54..2ca7efbe591 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderView.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderView.h @@ -23,7 +23,6 @@ #define RenderView_h #include "core/frame/FrameView.h" -#include "core/rendering/LayoutIndicator.h" #include "core/rendering/LayoutState.h" #include "core/rendering/RenderBlockFlow.h" #include "platform/PODFreeListArena.h" @@ -32,11 +31,9 @@ namespace WebCore { -class CustomFilterGlobalContext; class FlowThreadController; class RenderLayerCompositor; class RenderQuote; -class RenderWidget; // The root of the render tree, corresponding to the CSS initial containing block. // It's dimensions match that of the logical viewport (which may be different from @@ -54,7 +51,7 @@ public: virtual bool isRenderView() const OVERRIDE { return true; } - virtual bool requiresLayer() const OVERRIDE { return true; } + virtual LayerType layerTypeRequired() const OVERRIDE { return NormalLayer; } virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; @@ -62,31 +59,28 @@ public: virtual void updateLogicalWidth() OVERRIDE; virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE; - virtual bool supportsPartialLayout() const OVERRIDE { return true; } - virtual LayoutUnit availableLogicalHeight(AvailableLogicalHeightType) const OVERRIDE; // The same as the FrameView's layoutHeight/layoutWidth but with null check guards. - int viewHeight(ScrollableArea::IncludeScrollbarsInRect scrollbarInclusion = ScrollableArea::ExcludeScrollbars) const; - int viewWidth(ScrollableArea::IncludeScrollbarsInRect scrollbarInclusion = ScrollableArea::ExcludeScrollbars) const; - int viewLogicalWidth(ScrollableArea::IncludeScrollbarsInRect scrollbarInclusion = ScrollableArea::ExcludeScrollbars) const + int viewHeight(IncludeScrollbarsInRect = ExcludeScrollbars) const; + int viewWidth(IncludeScrollbarsInRect = ExcludeScrollbars) const; + int viewLogicalWidth() const { - return style()->isHorizontalWritingMode() ? viewWidth(scrollbarInclusion) : viewHeight(scrollbarInclusion); + return style()->isHorizontalWritingMode() ? viewWidth(ExcludeScrollbars) : viewHeight(ExcludeScrollbars); } - int viewLogicalHeight(ScrollableArea::IncludeScrollbarsInRect scrollbarInclusion = ScrollableArea::ExcludeScrollbars) const; + int viewLogicalHeight() const; + LayoutUnit viewLogicalHeightForPercentages() const; float zoomFactor() const; FrameView* frameView() const { return m_frameView; } - virtual void computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect&, bool fixed = false) const OVERRIDE; + virtual void mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect&, bool fixed = false) const OVERRIDE; void repaintViewRectangle(const LayoutRect&) const; - // 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. - void repaintRectangleInViewAndCompositedLayers(const LayoutRect&); + void repaintViewAndCompositedLayers(); - virtual void paint(PaintInfo&, const LayoutPoint&); + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&) OVERRIDE; enum SelectionRepaintMode { RepaintNewXOROld, RepaintNewMinusOld, RepaintNothing }; @@ -99,61 +93,50 @@ public: void selectionStartEnd(int& startPos, int& endPos) const; void repaintSelection() const; - virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const; - virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; - - void setMaximalOutlineSize(int o); - int maximalOutlineSize() const { return m_maximalOutlineSize; } - - void setOldMaximalOutlineSize(int o) { m_oldMaximalOutlineSize = o; } - int oldMaximalOutlineSize() const { return m_oldMaximalOutlineSize; } + virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const OVERRIDE; + virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const OVERRIDE; virtual LayoutRect viewRect() const OVERRIDE; - void updateWidgetPositions(); - void addWidget(RenderWidget*); - void removeWidget(RenderWidget*); - // layoutDelta is used transiently during layout to store how far an object has moved from its // last layout location, in order to repaint correctly. // If we're doing a full repaint m_layoutState will be 0, but in that case layoutDelta doesn't matter. LayoutSize layoutDelta() const { - return m_layoutState ? m_layoutState->m_layoutDelta : LayoutSize(); + ASSERT(!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()); + return m_layoutState ? m_layoutState->layoutDelta() : LayoutSize(); } void addLayoutDelta(const LayoutSize& delta) { - if (m_layoutState) { - m_layoutState->m_layoutDelta += delta; -#if !ASSERT_DISABLED - m_layoutState->m_layoutDeltaXSaturated |= m_layoutState->m_layoutDelta.width() == LayoutUnit::max() || m_layoutState->m_layoutDelta.width() == LayoutUnit::min(); - m_layoutState->m_layoutDeltaYSaturated |= m_layoutState->m_layoutDelta.height() == LayoutUnit::max() || m_layoutState->m_layoutDelta.height() == LayoutUnit::min(); -#endif - } + ASSERT(!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()); + if (m_layoutState) + m_layoutState->addLayoutDelta(delta); } -#if !ASSERT_DISABLED +#if ASSERT_ENABLED bool layoutDeltaMatches(const LayoutSize& delta) { + ASSERT(!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()); if (!m_layoutState) return false; - return (delta.width() == m_layoutState->m_layoutDelta.width() || m_layoutState->m_layoutDeltaXSaturated) && (delta.height() == m_layoutState->m_layoutDelta.height() || m_layoutState->m_layoutDeltaYSaturated); + return (delta.width() == m_layoutState->layoutDelta().width() || m_layoutState->layoutDeltaXSaturated()) && (delta.height() == m_layoutState->layoutDelta().height() || m_layoutState->layoutDeltaYSaturated()); } #endif - bool doingFullRepaint() const { return m_frameView->needsFullRepaint(); } - - // Subtree push/pop - void pushLayoutState(RenderObject*); - void popLayoutState(RenderObject*) { return popLayoutState(); } // Just doing this to keep popLayoutState() private and to make the subtree calls symmetrical. - - bool shouldDisableLayoutStateForSubtree(RenderObject*) const; + bool shouldDoFullRepaintForNextLayout() const; + bool doingFullRepaint() const { return m_frameView->needsFullPaintInvalidation(); } // Returns true if layoutState should be used for its cached offset and clip. - bool layoutStateEnabled() const { return m_layoutStateDisableCount == 0 && m_layoutState; } + bool layoutStateCachedOffsetsEnabled() const { return m_layoutState && m_layoutState->cachedOffsetsEnabled(); } LayoutState* layoutState() const { return m_layoutState; } - virtual void updateHitTestResult(HitTestResult&, const LayoutPoint&); + bool canMapUsingLayoutStateForContainer(const RenderObject* repaintContainer) const + { + // FIXME: LayoutState should be enabled for other repaint containers than the RenderView. crbug.com/363834 + return layoutStateCachedOffsetsEnabled() && (repaintContainer == this); + } + + virtual void updateHitTestResult(HitTestResult&, const LayoutPoint&) OVERRIDE; LayoutUnit pageLogicalHeight() const { return m_pageLogicalHeight; } void setPageLogicalHeight(LayoutUnit height) @@ -163,6 +146,7 @@ public: m_pageLogicalHeightChanged = true; } } + bool pageLogicalHeightChanged() const { return m_pageLogicalHeightChanged; } // Notification that this view moved into or out of a native window. void setIsInWindow(bool); @@ -170,8 +154,6 @@ public: RenderLayerCompositor* compositor(); bool usesCompositing() const; - CustomFilterGlobalContext* customFilterGlobalContext(); - IntRect unscaledDocumentRect() const; LayoutRect backgroundRect(RenderBox* backgroundRenderer) const; @@ -180,12 +162,8 @@ public: // Renderer that paints the root background has background-images which all have background-attachment: fixed. bool rootBackgroundIsEntirelyFixed() const; - bool hasRenderNamedFlowThreads() const; - bool checkTwoPassLayoutForAutoHeightRegions() const; FlowThreadController* flowThreadController(); - void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - IntervalArena* intervalArena(); void setRenderQuoteHead(RenderQuote* head) { m_renderQuoteHead = head; } @@ -199,81 +177,39 @@ public: void removeRenderCounter() { ASSERT(m_renderCounterCount > 0); m_renderCounterCount--; } bool hasRenderCounters() { return m_renderCounterCount; } - virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0) OVERRIDE; + virtual bool backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const OVERRIDE; - virtual bool backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const OVERRIDE FINAL; - - LayoutUnit viewportPercentageWidth(float percentage) const; - LayoutUnit viewportPercentageHeight(float percentage) const; - LayoutUnit viewportPercentageMin(float percentage) const; - LayoutUnit viewportPercentageMax(float percentage) const; + double layoutViewportWidth() const; + double layoutViewportHeight() const; + void pushLayoutState(LayoutState&); + void popLayoutState(); private: virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE; virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE; - virtual void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const; - virtual bool requiresColumns(int desiredColumnCount) const OVERRIDE; + virtual void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const OVERRIDE; virtual void computeSelfHitTestRects(Vector<LayoutRect>&, const LayoutPoint& layerOffset) const OVERRIDE; - bool initializeLayoutState(LayoutState&); - - virtual void calcColumnWidth() OVERRIDE; - virtual ColumnInfo::PaginationUnit paginationUnit() const OVERRIDE; + virtual void invalidateTreeAfterLayout(const RenderLayerModelObject& paintInvalidationContainer) OVERRIDE FINAL; bool shouldRepaint(const LayoutRect&) const; - // These functions may only be accessed by LayoutStateMaintainer. - bool pushLayoutState(RenderBox* renderer, const LayoutSize& offset, LayoutUnit pageHeight = 0, bool pageHeightChanged = false, ColumnInfo* colInfo = 0) - { - // We push LayoutState even if layoutState is disabled because it stores layoutDelta too. - if (!doingFullRepaint() || m_layoutState->isPaginated() || renderer->hasColumns() || renderer->flowThreadContainingBlock() - || m_layoutState->lineGrid() || (renderer->style()->lineGrid() != RenderStyle::initialLineGrid() && renderer->isRenderBlockFlow()) - || (renderer->isRenderBlock() && toRenderBlock(renderer)->shapeInsideInfo()) - || (m_layoutState->shapeInsideInfo() && renderer->isRenderBlock() && !toRenderBlock(renderer)->allowsShapeInsideInfoSharing(m_layoutState->shapeInsideInfo()->owner())) - ) { - pushLayoutStateForCurrentFlowThread(renderer); - m_layoutState = new LayoutState(m_layoutState, renderer, offset, pageHeight, pageHeightChanged, colInfo); - return true; - } - return false; - } - - void popLayoutState() - { - LayoutState* state = m_layoutState; - m_layoutState = state->m_next; - delete state; - popLayoutStateForCurrentFlowThread(); - } - - // Suspends the LayoutState optimization. Used under transforms that cannot be represented by - // LayoutState (common in SVG) and when manipulating the render tree during layout in ways - // that can trigger repaint of a non-child (e.g. when a list item moves its list marker around). - // Note that even when disabled, LayoutState is still used to store layoutDelta. - // These functions may only be accessed by LayoutStateMaintainer or LayoutStateDisabler. - void disableLayoutState() { m_layoutStateDisableCount++; } - void enableLayoutState() { ASSERT(m_layoutStateDisableCount > 0); m_layoutStateDisableCount--; } + bool rootFillsViewportBackground(RenderBox* rootBox) const; - void layoutContent(const LayoutState&); - void layoutContentInAutoLogicalHeightRegions(const LayoutState&); + void layoutContent(); #ifndef NDEBUG - void checkLayoutState(const LayoutState&); + void checkLayoutState(); #endif void positionDialog(RenderBox*); void positionDialogs(); - size_t getRetainedWidgets(Vector<RenderWidget*>&); - void releaseWidgets(Vector<RenderWidget*>&); - - void pushLayoutStateForCurrentFlowThread(const RenderObject*); - void popLayoutStateForCurrentFlowThread(); - - friend class LayoutStateMaintainer; - friend class LayoutStateDisabler; + friend class ForceHorriblySlowRectMapping; bool shouldUsePrintingLayout() const; + RenderObject* backgroundRenderer() const; + FrameView* m_frameView; RenderObject* m_selectionStart; @@ -282,18 +218,10 @@ private: int m_selectionStartPos; int m_selectionEndPos; - int m_maximalOutlineSize; // Used to apply a fudge factor to dirty-rect checks on blocks/tables. - int m_oldMaximalOutlineSize; // The fudge factor from the previous layout. - - typedef HashSet<RenderWidget*> RenderWidgetSet; - RenderWidgetSet m_widgets; - LayoutUnit m_pageLogicalHeight; bool m_pageLogicalHeightChanged; LayoutState* m_layoutState; - unsigned m_layoutStateDisableCount; OwnPtr<RenderLayerCompositor> m_compositor; - OwnPtr<CustomFilterGlobalContext> m_customFilterGlobalContext; OwnPtr<FlowThreadController> m_flowThreadController; RefPtr<IntervalArena> m_intervalArena; @@ -303,99 +231,35 @@ private: DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderView, isRenderView()); -// Stack-based class to assist with LayoutState push/pop -class LayoutStateMaintainer { - WTF_MAKE_NONCOPYABLE(LayoutStateMaintainer); +// Suspends the LayoutState cached offset and clipRect optimization. Used under transforms +// that cannot be represented by LayoutState (common in SVG) and when manipulating the render +// tree during layout in ways that can trigger repaint of a non-child (e.g. when a list item +// moves its list marker around). Note that even when disabled, LayoutState is still used to +// store layoutDelta. +class ForceHorriblySlowRectMapping { + WTF_MAKE_NONCOPYABLE(ForceHorriblySlowRectMapping); public: - // ctor to push now - LayoutStateMaintainer(RenderView* view, RenderBox* root, LayoutSize offset, bool disableState = false, LayoutUnit pageHeight = 0, bool pageHeightChanged = false, ColumnInfo* colInfo = 0) - : m_view(view) - , m_disabled(disableState) - , m_didStart(false) - , m_didEnd(false) - , m_didCreateLayoutState(false) + ForceHorriblySlowRectMapping(const RenderObject& root) + : m_view(*root.view()) + , m_didDisable(m_view.layoutState() && m_view.layoutState()->cachedOffsetsEnabled()) { - push(root, offset, pageHeight, pageHeightChanged, colInfo); - } - - // ctor to maybe push later - LayoutStateMaintainer(RenderView* view) - : m_view(view) - , m_disabled(false) - , m_didStart(false) - , m_didEnd(false) - , m_didCreateLayoutState(false) - { - } - - ~LayoutStateMaintainer() - { - ASSERT(m_didStart == m_didEnd); // if this fires, it means that someone did a push(), but forgot to pop(). - } - - void push(RenderBox* root, LayoutSize offset, LayoutUnit pageHeight = 0, bool pageHeightChanged = false, ColumnInfo* colInfo = 0) - { - ASSERT(!m_didStart); - // We push state even if disabled, because we still need to store layoutDelta - m_didCreateLayoutState = m_view->pushLayoutState(root, offset, pageHeight, pageHeightChanged, colInfo); - if (m_disabled && m_didCreateLayoutState) - m_view->disableLayoutState(); - m_didStart = true; - } - - void pop() - { - if (m_didStart) { - ASSERT(!m_didEnd); - if (m_didCreateLayoutState) { - m_view->popLayoutState(); - if (m_disabled) - m_view->enableLayoutState(); - } - - m_didEnd = true; - } - } - - bool didPush() const { return m_didStart; } - -private: - RenderView* m_view; - bool m_disabled : 1; // true if the offset and clip part of layoutState is disabled - bool m_didStart : 1; // true if we did a push or disable - bool m_didEnd : 1; // true if we popped or re-enabled - bool m_didCreateLayoutState : 1; // true if we actually made a layout state. -}; - -class LayoutStateDisabler { - WTF_MAKE_NONCOPYABLE(LayoutStateDisabler); -public: - LayoutStateDisabler(RenderView* view) - : m_view(view) - { - if (m_view) - m_view->disableLayoutState(); + if (m_view.layoutState()) + m_view.layoutState()->m_cachedOffsetsEnabled = false; +#if ASSERT_ENABLED + m_layoutState = m_view.layoutState(); +#endif } - ~LayoutStateDisabler() + ~ForceHorriblySlowRectMapping() { - if (m_view) - m_view->enableLayoutState(); + ASSERT(m_view.layoutState() == m_layoutState); + if (m_didDisable) + m_view.layoutState()->m_cachedOffsetsEnabled = true; } private: - RenderView* m_view; -}; - -class FragmentationDisabler { - WTF_MAKE_NONCOPYABLE(FragmentationDisabler); -public: - FragmentationDisabler(RenderObject* root); - ~FragmentationDisabler(); -private: - RenderObject* m_root; - RenderObject::FlowThreadState m_flowThreadState; - bool m_fragmenting; -#ifndef NDEBUG + RenderView& m_view; + bool m_didDisable; +#if ASSERT_ENABLED LayoutState* m_layoutState; #endif }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderWidget.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderWidget.cpp index 90b089686a8..43ecbdf8a8b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderWidget.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderWidget.cpp @@ -25,89 +25,42 @@ #include "core/rendering/RenderWidget.h" #include "core/accessibility/AXObjectCache.h" -#include "core/frame/Frame.h" -#include "core/rendering/CompositedLayerMapping.h" +#include "core/frame/LocalFrame.h" +#include "core/html/HTMLFrameOwnerElement.h" +#include "core/html/HTMLPlugInElement.h" #include "core/rendering/GraphicsContextAnnotator.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderView.h" -#include "platform/graphics/GraphicsContext.h" +#include "core/rendering/compositing/CompositedLayerMapping.h" +#include "core/rendering/compositing/RenderLayerCompositor.h" #include "wtf/HashMap.h" namespace WebCore { -typedef HashMap<RefPtr<Widget>, FrameView*> WidgetToParentMap; -static WidgetToParentMap& widgetNewParentMap() -{ - DEFINE_STATIC_LOCAL(WidgetToParentMap, map, ()); - return map; -} - -static unsigned s_updateSuspendCount = 0; - -RenderWidget::UpdateSuspendScope::UpdateSuspendScope() -{ - ++s_updateSuspendCount; -} - -RenderWidget::UpdateSuspendScope::~UpdateSuspendScope() -{ - ASSERT(s_updateSuspendCount > 0); - if (s_updateSuspendCount == 1) { - WidgetToParentMap map; - widgetNewParentMap().swap(map); - WidgetToParentMap::iterator end = map.end(); - for (WidgetToParentMap::iterator it = map.begin(); it != end; ++it) { - Widget* child = it->key.get(); - ScrollView* currentParent = toScrollView(child->parent()); - FrameView* newParent = it->value; - if (newParent != currentParent) { - if (currentParent) - currentParent->removeChild(child); - if (newParent) - newParent->addChild(child); - } - } - } - --s_updateSuspendCount; -} - -static void moveWidgetToParentSoon(Widget* child, FrameView* parent) -{ - if (!s_updateSuspendCount) { - if (parent) - parent->addChild(child); - else - toScrollView(child->parent())->removeChild(child); - return; - } - widgetNewParentMap().set(child, parent); -} - RenderWidget::RenderWidget(Element* element) : RenderReplaced(element) - , m_widget(0) - , m_frameView(element->document().view()) // Reference counting is used to prevent the widget from being // destroyed while inside the Widget code, which might not be // able to handle that. , m_refCount(1) { - view()->addWidget(this); + ASSERT(element); + frameView()->addWidget(this); } void RenderWidget::willBeDestroyed() { - if (RenderView* v = view()) - v->removeWidget(this); + frameView()->removeWidget(this); if (AXObjectCache* cache = document().existingAXObjectCache()) { cache->childrenChanged(this->parent()); cache->remove(this); } - setWidget(0); + Element* element = toElement(node()); + if (element && element->isFrameOwnerElement()) + toHTMLFrameOwnerElement(element)->setWidget(nullptr); RenderReplaced::willBeDestroyed(); } @@ -122,7 +75,17 @@ void RenderWidget::destroy() RenderWidget::~RenderWidget() { ASSERT(m_refCount <= 0); - clearWidget(); +} + +Widget* RenderWidget::widget() const +{ + // Plugin widgets are stored in their DOM node. This includes HTMLAppletElement. + Element* element = toElement(node()); + + if (element && element->isFrameOwnerElement()) + return toHTMLFrameOwnerElement(element)->ownedWidget(); + + return 0; } // Widgets are always placed on integer boundaries, so rounding the size is actually @@ -138,35 +101,28 @@ bool RenderWidget::setWidgetGeometry(const LayoutRect& frame) if (!node()) return false; - IntRect clipRect = roundedIntRect(enclosingLayer()->childrenClipRect()); + Widget* widget = this->widget(); + ASSERT(widget); + IntRect newFrame = roundedIntRect(frame); - bool clipChanged = m_clipRect != clipRect; - bool frameRectChanged = m_widget->frameRect() != newFrame; - if (!frameRectChanged && !clipChanged) + if (widget->frameRect() == newFrame) return false; - m_clipRect = clipRect; - RefPtr<RenderWidget> protector(this); - RefPtr<Node> protectedNode(node()); - m_widget->setFrameRect(newFrame); - - if (clipChanged && !frameRectChanged) - m_widget->clipRectChanged(); - - if (hasLayer() && layer()->compositingState() == PaintsIntoOwnBacking) - layer()->compositedLayerMapping()->updateAfterWidgetResize(); - - bool boundsChanged = m_widget->frameRect().size() != newFrame.size(); - return boundsChanged; + RefPtrWillBeRawPtr<Node> protectedNode(node()); + widget->setFrameRect(newFrame); + return widget->frameRect().size() != newFrame.size(); } bool RenderWidget::updateWidgetGeometry() { + Widget* widget = this->widget(); + ASSERT(widget); + LayoutRect contentBox = contentBoxRect(); LayoutRect absoluteContentBox(localToAbsoluteQuad(FloatQuad(contentBox)).boundingBox()); - if (m_widget->isFrameView()) { + if (widget->isFrameView()) { contentBox.setLocation(absoluteContentBox.location()); return setWidgetGeometry(contentBox); } @@ -174,54 +130,24 @@ bool RenderWidget::updateWidgetGeometry() return setWidgetGeometry(absoluteContentBox); } -void RenderWidget::setWidget(PassRefPtr<Widget> widget) -{ - if (widget == m_widget) - return; - - if (m_widget) { - moveWidgetToParentSoon(m_widget.get(), 0); - clearWidget(); - } - m_widget = widget; - if (m_widget) { - // If we've already received a layout, apply the calculated space to the - // widget immediately, but we have to have really been fully constructed (with a non-null - // style pointer). - if (style()) { - if (!needsLayout()) - updateWidgetGeometry(); - - if (style()->visibility() != VISIBLE) - m_widget->hide(); - else { - m_widget->show(); - repaint(); - } - } - moveWidgetToParentSoon(m_widget.get(), m_frameView); - } - - if (AXObjectCache* cache = document().existingAXObjectCache()) - cache->childrenChanged(this); -} - void RenderWidget::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); clearNeedsLayout(); } void RenderWidget::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderReplaced::styleDidChange(diff, oldStyle); - if (m_widget) { - if (style()->visibility() != VISIBLE) - m_widget->hide(); - else - m_widget->show(); + Widget* widget = this->widget(); + + if (widget) { + if (style()->visibility() != VISIBLE) { + widget->hide(); + } else { + widget->show(); + } } } @@ -229,9 +155,12 @@ void RenderWidget::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintO { LayoutPoint adjustedPaintOffset = paintOffset + location(); + Widget* widget = this->widget(); + ASSERT(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. - IntPoint widgetLocation = m_widget->frameRect().location(); + IntPoint widgetLocation = widget->frameRect().location(); IntPoint paintLocation(roundToInt(adjustedPaintOffset.x() + borderLeft() + paddingLeft()), roundToInt(adjustedPaintOffset.y() + borderTop() + paddingTop())); IntRect paintRect = paintInfo.rect; @@ -240,20 +169,20 @@ void RenderWidget::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintO // 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()) { - paintInfo.context->translate(widgetPaintOffset); + paintInfo.context->translate(widgetPaintOffset.width(), widgetPaintOffset.height()); paintRect.move(-widgetPaintOffset); } - m_widget->paint(paintInfo.context, paintRect); + widget->paint(paintInfo.context, paintRect); if (!widgetPaintOffset.isZero()) - paintInfo.context->translate(-widgetPaintOffset); + paintInfo.context->translate(-widgetPaintOffset.width(), -widgetPaintOffset.height()); - if (m_widget->isFrameView()) { - FrameView* frameView = toFrameView(m_widget.get()); + if (widget->isFrameView()) { + FrameView* frameView = toFrameView(widget); bool runOverlapTests = !frameView->useSlowRepaintsIfNotOverlapped() || frameView->hasCompositedContent(); if (paintInfo.overlapTestRequests && runOverlapTests) { ASSERT(!paintInfo.overlapTestRequests->contains(this)); - paintInfo.overlapTestRequests->set(this, m_widget->frameRect()); + paintInfo.overlapTestRequests->set(this, widget->frameRect()); } } } @@ -278,7 +207,7 @@ void RenderWidget::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && hasOutline()) paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, size())); - if (!m_frameView || paintInfo.phase != PaintPhaseForeground) + if (paintInfo.phase != PaintPhaseForeground) return; if (style()->hasBorderRadius()) { @@ -294,7 +223,8 @@ void RenderWidget::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) clipRoundedInnerRect(paintInfo.context, borderRect, roundedInnerRect); } - if (m_widget) + Widget* widget = this->widget(); + if (widget) paintContents(paintInfo, paintOffset); if (style()->hasBorderRadius()) @@ -312,9 +242,10 @@ void RenderWidget::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) void RenderWidget::setIsOverlapped(bool isOverlapped) { - ASSERT(m_widget); - ASSERT(m_widget->isFrameView()); - toFrameView(m_widget.get())->setIsOverlapped(isOverlapped); + Widget* widget = this->widget(); + ASSERT(widget); + ASSERT(widget->isFrameView()); + toFrameView(widget)->setIsOverlapped(isOverlapped); } void RenderWidget::deref() @@ -323,17 +254,39 @@ void RenderWidget::deref() postDestroy(); } +void RenderWidget::updateOnWidgetChange() +{ + Widget* widget = this->widget(); + if (!widget) + return; + + if (!style()) + return; + + if (!needsLayout()) + updateWidgetGeometry(); + + if (style()->visibility() != VISIBLE) { + widget->hide(); + } else { + widget->show(); + // FIXME: Why do we repaint in this case, but not the other? + paintInvalidationForWholeRenderer(); + } +} + void RenderWidget::updateWidgetPosition() { - if (!m_widget || !node()) // Check the node in case destroy() has been called. + Widget* widget = this->widget(); + if (!widget || !node()) // Check the node in case destroy() has been called. return; bool boundsChanged = updateWidgetGeometry(); // if the frame bounds got changed, or if view needs layout (possibly indicating // content size is wrong) we have to do a layout to set the right widget size - if (m_widget && m_widget->isFrameView()) { - FrameView* frameView = toFrameView(m_widget.get()); + if (widget && widget->isFrameView()) { + FrameView* frameView = toFrameView(widget); // Check the frame's page to make sure that the frame isn't in the process of being destroyed. if ((boundsChanged || frameView->needsLayout()) && frameView->frame().page()) frameView->layout(); @@ -342,14 +295,10 @@ void RenderWidget::updateWidgetPosition() void RenderWidget::widgetPositionsUpdated() { - if (!m_widget) + Widget* widget = this->widget(); + if (!widget) return; - m_widget->widgetPositionsUpdated(); -} - -void RenderWidget::clearWidget() -{ - m_widget = 0; + widget->widgetPositionsUpdated(); } bool RenderWidget::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderWidget.h b/chromium/third_party/WebKit/Source/core/rendering/RenderWidget.h index 2cde8486906..7c29616245d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderWidget.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderWidget.h @@ -31,9 +31,9 @@ class RenderWidget : public RenderReplaced { public: virtual ~RenderWidget(); - Widget* widget() const { return m_widget.get(); } - virtual void setWidget(PassRefPtr<Widget>); + Widget* widget() const; + void updateOnWidgetChange(); void updateWidgetPosition(); void widgetPositionsUpdated(); @@ -42,37 +42,26 @@ public: void ref() { ++m_refCount; } void deref(); - class UpdateSuspendScope { - public: - UpdateSuspendScope(); - ~UpdateSuspendScope(); - }; + virtual bool isWidget() const OVERRIDE FINAL { return true; } + bool updateWidgetGeometry(); protected: explicit RenderWidget(Element*); - void clearWidget(); - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE FINAL; - virtual void layout(); - virtual void paint(PaintInfo&, const LayoutPoint&); - virtual CursorDirective getCursor(const LayoutPoint&, Cursor&) const; + virtual void layout() OVERRIDE; + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; + virtual CursorDirective getCursor(const LayoutPoint&, Cursor&) const OVERRIDE FINAL; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; virtual void paintContents(PaintInfo&, const LayoutPoint&); private: - virtual bool isWidget() const OVERRIDE FINAL { return true; } - virtual void willBeDestroyed() OVERRIDE FINAL; virtual void destroy() OVERRIDE FINAL; bool setWidgetGeometry(const LayoutRect&); - bool updateWidgetGeometry(); - RefPtr<Widget> m_widget; - FrameView* m_frameView; - IntRect m_clipRect; // The rectangle needs to remain correct after scrolling, so it is stored in content view coordinates, and not clipped to window. int m_refCount; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderWordBreak.h b/chromium/third_party/WebKit/Source/core/rendering/RenderWordBreak.h index acf3c6075d0..d5b0d31c73d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderWordBreak.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderWordBreak.h @@ -37,8 +37,8 @@ class RenderWordBreak FINAL : public RenderText { public: explicit RenderWordBreak(HTMLElement*); - virtual const char* renderName() const; - virtual bool isWordBreak() const; + virtual const char* renderName() const OVERRIDE; + virtual bool isWordBreak() const OVERRIDE; }; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/RootInlineBox.cpp b/chromium/third_party/WebKit/Source/core/rendering/RootInlineBox.cpp index 871cf0ff1ad..5b0a8fde96c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RootInlineBox.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RootInlineBox.cpp @@ -47,7 +47,7 @@ COMPILE_ASSERT(sizeof(RootInlineBox) == sizeof(SameSizeAsRootInlineBox), RootInl typedef WTF::HashMap<const RootInlineBox*, EllipsisBox*> EllipsisBoxMap; static EllipsisBoxMap* gEllipsisBoxMap = 0; -RootInlineBox::RootInlineBox(RenderBlockFlow* block) +RootInlineBox::RootInlineBox(RenderBlockFlow& block) : InlineFlowBox(block) , m_lineBreakPos(0) , m_lineBreakObj(0) @@ -56,7 +56,7 @@ RootInlineBox::RootInlineBox(RenderBlockFlow* block) , m_lineTopWithLeading(0) , m_lineBottomWithLeading(0) { - setIsHorizontal(block->isHorizontalWritingMode()); + setIsHorizontal(block.isHorizontalWritingMode()); } @@ -78,7 +78,7 @@ void RootInlineBox::detachEllipsisBox() RenderLineBoxList* RootInlineBox::rendererLineBoxes() const { - return block()->lineBoxes(); + return block().lineBoxes(); } void RootInlineBox::clearTruncation() @@ -164,7 +164,7 @@ float RootInlineBox::placeEllipsisBox(bool ltr, float blockLeftEdge, float block void RootInlineBox::paintEllipsisBox(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) const { - if (hasEllipsisBox() && paintInfo.shouldPaintWithinRoot(renderer()) && renderer()->style()->visibility() == VISIBLE + if (hasEllipsisBox() && paintInfo.shouldPaintWithinRoot(&renderer()) && renderer().style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) ellipsisBox()->paint(paintInfo, paintOffset, lineTop, lineBottom); } @@ -179,7 +179,7 @@ bool RootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re { if (hasEllipsisBox() && visibleToHitTestRequest(request)) { if (ellipsisBox()->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom)) { - renderer()->updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); + renderer().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); return true; } } @@ -200,38 +200,15 @@ void RootInlineBox::adjustPosition(float dx, float dy) void RootInlineBox::childRemoved(InlineBox* box) { - if (box->renderer() == m_lineBreakObj) + if (&box->renderer() == m_lineBreakObj) setLineBreakInfo(0, 0, BidiStatus()); - for (RootInlineBox* prev = prevRootBox(); prev && prev->lineBreakObj() == box->renderer(); prev = prev->prevRootBox()) { + for (RootInlineBox* prev = prevRootBox(); prev && prev->lineBreakObj() == &box->renderer(); prev = prev->prevRootBox()) { prev->setLineBreakInfo(0, 0, BidiStatus()); prev->markDirty(); } } -RenderRegion* RootInlineBox::containingRegion() const -{ - RenderRegion* region = m_fragmentationData ? m_fragmentationData->m_containingRegion : 0; - -#ifndef NDEBUG - if (region) { - RenderFlowThread* flowThread = block()->flowThreadContainingBlock(); - const RenderRegionList& regionList = flowThread->renderRegionList(); - ASSERT(regionList.contains(region)); - } -#endif - - return region; -} - -void RootInlineBox::setContainingRegion(RenderRegion* region) -{ - ASSERT(!isDirty()); - ASSERT(block()->flowThreadContainingBlock()); - LineFragmentationData* fragmentationData = ensureLineFragmentationData(); - fragmentationData->m_containingRegion = region; -} - LayoutUnit RootInlineBox::alignBoxesInBlockDirection(LayoutUnit heightOfBlock, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache) { // SVG will handle vertical alignment on its own. @@ -246,7 +223,7 @@ LayoutUnit RootInlineBox::alignBoxesInBlockDirection(LayoutUnit heightOfBlock, G bool setMaxDescent = false; // Figure out if we're in no-quirks mode. - bool noQuirksMode = renderer()->document().inNoQuirksMode(); + bool noQuirksMode = renderer().document().inNoQuirksMode(); m_baselineType = requiresIdeographicBaseline(textBoxDataMap) ? IdeographicBaseline : AlphabeticBaseline; @@ -272,22 +249,17 @@ LayoutUnit RootInlineBox::alignBoxesInBlockDirection(LayoutUnit heightOfBlock, G maxHeight = max<LayoutUnit>(0, maxHeight); // FIXME: Is this really necessary? setLineTopBottomPositions(lineTop, lineBottom, heightOfBlock, heightOfBlock + maxHeight); - setPaginatedLineWidth(block()->availableLogicalWidthForContent(heightOfBlock)); + if (block().view()->layoutState()->isPaginated()) + setPaginatedLineWidth(block().availableLogicalWidthForContent()); 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. - adjustBlockDirectionPosition(annotationsAdjustment); + adjustBlockDirectionPosition(annotationsAdjustment.toFloat()); heightOfBlock += annotationsAdjustment; } - LayoutUnit gridSnapAdjustment = lineSnapAdjustment(); - if (gridSnapAdjustment) { - adjustBlockDirectionPosition(gridSnapAdjustment); - heightOfBlock += gridSnapAdjustment; - } - return heightOfBlock + maxHeight; } @@ -302,7 +274,7 @@ LayoutUnit RootInlineBox::beforeAnnotationsAdjustment() const { LayoutUnit result = 0; - if (!renderer()->style()->isFlippedLinesWritingMode()) { + if (!renderer().style()->isFlippedLinesWritingMode()) { // Annotations under the previous line may push us down. if (prevRootBox() && prevRootBox()->hasAnnotationsAfter()) result = prevRootBox()->computeUnderAnnotationAdjustment(lineTop()); @@ -311,12 +283,12 @@ LayoutUnit RootInlineBox::beforeAnnotationsAdjustment() const return result; // Annotations over this line may push us further down. - LayoutUnit highestAllowedPosition = prevRootBox() ? min(prevRootBox()->lineBottom(), lineTop()) + result : static_cast<LayoutUnit>(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() : static_cast<LayoutUnit>(block()->borderBefore())); + result = computeUnderAnnotationAdjustment(prevRootBox() ? prevRootBox()->lineBottom() : static_cast<LayoutUnit>(block().borderBefore())); if (!prevRootBox() || !prevRootBox()->hasAnnotationsAfter()) return result; @@ -329,115 +301,26 @@ LayoutUnit RootInlineBox::beforeAnnotationsAdjustment() const return result; } -LayoutUnit RootInlineBox::lineSnapAdjustment(LayoutUnit delta) const -{ - // If our block doesn't have snapping turned on, do nothing. - // FIXME: Implement bounds snapping. - if (block()->style()->lineSnap() == LineSnapNone) - return 0; - - // Get the current line grid and offset. - LayoutState* layoutState = block()->view()->layoutState(); - RenderBlockFlow* lineGrid = layoutState->lineGrid(); - LayoutSize lineGridOffset = layoutState->lineGridOffset(); - if (!lineGrid || lineGrid->style()->writingMode() != block()->style()->writingMode()) - return 0; - - // Get the hypothetical line box used to establish the grid. - RootInlineBox* lineGridBox = lineGrid->lineGridBox(); - if (!lineGridBox) - return 0; - - LayoutUnit lineGridBlockOffset = lineGrid->isHorizontalWritingMode() ? lineGridOffset.height() : lineGridOffset.width(); - LayoutUnit blockOffset = block()->isHorizontalWritingMode() ? layoutState->layoutOffset().height() : layoutState->layoutOffset().width(); - - // Now determine our position on the grid. Our baseline needs to be adjusted to the nearest baseline multiple - // as established by the line box. - // FIXME: Need to handle crazy line-box-contain values that cause the root line box to not be considered. I assume - // the grid should honor line-box-contain. - LayoutUnit gridLineHeight = lineGridBox->lineBottomWithLeading() - lineGridBox->lineTopWithLeading(); - if (!gridLineHeight) - return 0; - - LayoutUnit lineGridFontAscent = lineGrid->style()->fontMetrics().ascent(baselineType()); - LayoutUnit lineGridFontHeight = lineGridBox->logicalHeight(); - LayoutUnit firstTextTop = lineGridBlockOffset + lineGridBox->logicalTop(); - LayoutUnit firstLineTopWithLeading = lineGridBlockOffset + lineGridBox->lineTopWithLeading(); - LayoutUnit firstBaselinePosition = firstTextTop + lineGridFontAscent; - - LayoutUnit currentTextTop = blockOffset + logicalTop() + delta; - LayoutUnit currentFontAscent = block()->style()->fontMetrics().ascent(baselineType()); - LayoutUnit currentBaselinePosition = currentTextTop + currentFontAscent; - - LayoutUnit lineGridPaginationOrigin = isHorizontal() ? layoutState->lineGridPaginationOrigin().height() : layoutState->lineGridPaginationOrigin().width(); - - // If we're paginated, see if we're on a page after the first one. If so, the grid resets on subsequent pages. - // FIXME: If the grid is an ancestor of the pagination establisher, then this is incorrect. - LayoutUnit pageLogicalTop = 0; - if (layoutState->isPaginated() && layoutState->pageLogicalHeight()) { - pageLogicalTop = block()->pageLogicalTopForOffset(lineTopWithLeading() + delta); - if (pageLogicalTop > firstLineTopWithLeading) - firstTextTop = pageLogicalTop + lineGridBox->logicalTop() - lineGrid->borderBefore() - lineGrid->paddingBefore() + lineGridPaginationOrigin; - } - - if (block()->style()->lineSnap() == LineSnapContain) { - // Compute the desired offset from the text-top of a grid line. - // Look at our height (logicalHeight()). - // Look at the total available height. It's going to be (textBottom - textTop) + (n-1)*(multiple with leading) - // where n is number of grid lines required to enclose us. - if (logicalHeight() <= lineGridFontHeight) - firstTextTop += (lineGridFontHeight - logicalHeight()) / 2; - else { - LayoutUnit numberOfLinesWithLeading = ceilf(static_cast<float>(logicalHeight() - lineGridFontHeight) / gridLineHeight); - LayoutUnit totalHeight = lineGridFontHeight + numberOfLinesWithLeading * gridLineHeight; - firstTextTop += (totalHeight - logicalHeight()) / 2; - } - firstBaselinePosition = firstTextTop + currentFontAscent; - } else - firstBaselinePosition = firstTextTop + lineGridFontAscent; - - // If we're above the first line, just push to the first line. - if (currentBaselinePosition < firstBaselinePosition) - return delta + firstBaselinePosition - currentBaselinePosition; - - // Otherwise we're in the middle of the grid somewhere. Just push to the next line. - LayoutUnit baselineOffset = currentBaselinePosition - firstBaselinePosition; - LayoutUnit remainder = roundToInt(baselineOffset) % roundToInt(gridLineHeight); - LayoutUnit result = delta; - if (remainder) - result += gridLineHeight - remainder; - - // If we aren't paginated we can return the result. - if (!layoutState->isPaginated() || !layoutState->pageLogicalHeight() || result == delta) - return result; - - // We may end up shifted to a new page. We need to do a re-snap when that happens. - LayoutUnit newPageLogicalTop = block()->pageLogicalTopForOffset(lineBottomWithLeading() + result); - if (newPageLogicalTop == pageLogicalTop) - return result; - - // Put ourselves at the top of the next page to force a snap onto the new grid established by that page. - return lineSnapAdjustment(newPageLogicalTop - (blockOffset + lineTopWithLeading())); -} - GapRects RootInlineBox::lineSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, LayoutUnit selTop, LayoutUnit selHeight, const PaintInfo* paintInfo) { RenderObject::SelectionState lineState = selectionState(); bool leftGap, rightGap; - block()->getSelectionGapInfo(lineState, leftGap, rightGap); + block().getSelectionGapInfo(lineState, leftGap, rightGap); GapRects result; InlineBox* firstBox = firstSelectedBox(); InlineBox* lastBox = lastSelectedBox(); - if (leftGap) - result.uniteLeft(block()->logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, - firstBox->parent()->renderer(), firstBox->logicalLeft(), selTop, selHeight, paintInfo)); - if (rightGap) - result.uniteRight(block()->logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, - lastBox->parent()->renderer(), lastBox->logicalRight(), selTop, selHeight, paintInfo)); + if (leftGap) { + result.uniteLeft(block().logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, + &firstBox->parent()->renderer(), firstBox->logicalLeft(), selTop, selHeight, paintInfo)); + } + if (rightGap) { + result.uniteRight(block().logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, + &lastBox->parent()->renderer(), lastBox->logicalRight(), selTop, selHeight, paintInfo)); + } // When dealing with bidi text, a non-contiguous selection region is possible. // e.g. The logical text aaaAAAbbb (capitals denote RTL text and non-capitals LTR) is layed out @@ -453,11 +336,11 @@ GapRects RootInlineBox::lineSelectionGap(RenderBlock* rootBlock, const LayoutPoi for (InlineBox* box = firstBox->nextLeafChild(); box; box = box->nextLeafChild()) { if (box->selectionState() != RenderObject::SelectionNone) { LayoutRect logicalRect(lastLogicalLeft, selTop, box->logicalLeft() - lastLogicalLeft, selHeight); - logicalRect.move(renderer()->isHorizontalWritingMode() ? offsetFromRootBlock : LayoutSize(offsetFromRootBlock.height(), offsetFromRootBlock.width())); + logicalRect.move(renderer().isHorizontalWritingMode() ? offsetFromRootBlock : LayoutSize(offsetFromRootBlock.height(), offsetFromRootBlock.width())); LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect); if (isPreviousBoxSelected && gapRect.width() > 0 && gapRect.height() > 0) { - if (paintInfo && box->parent()->renderer()->style()->visibility() == VISIBLE) - paintInfo->context->fillRect(gapRect, box->parent()->renderer()->selectionBackgroundColor()); + if (paintInfo && box->parent()->renderer().style()->visibility() == VISIBLE) + paintInfo->context->fillRect(gapRect, box->parent()->renderer().selectionBackgroundColor()); // VisibleSelection may be non-contiguous, see comment above. result.uniteCenter(gapRect); } @@ -521,20 +404,20 @@ LayoutUnit RootInlineBox::selectionTop() const LayoutUnit selectionTop = m_lineTop; if (m_hasAnnotationsBefore) - selectionTop -= !renderer()->style()->isFlippedLinesWritingMode() ? computeOverAnnotationAdjustment(m_lineTop) : computeUnderAnnotationAdjustment(m_lineTop); + selectionTop -= !renderer().style()->isFlippedLinesWritingMode() ? computeOverAnnotationAdjustment(m_lineTop) : computeUnderAnnotationAdjustment(m_lineTop); - if (renderer()->style()->isFlippedLinesWritingMode()) + if (renderer().style()->isFlippedLinesWritingMode() || !prevRootBox()) return selectionTop; - LayoutUnit prevBottom = prevRootBox() ? prevRootBox()->selectionBottom() : block()->borderBefore() + block()->paddingBefore(); - if (prevBottom < selectionTop && block()->containsFloats()) { + LayoutUnit prevBottom = prevRootBox()->selectionBottom(); + if (prevBottom < selectionTop && block().containsFloats()) { // This line has actually been moved further down, probably from a large line-height, but possibly because the // line was forced to clear floats. If so, let's check the offsets, and only be willing to use the previous // line's bottom if the offsets are greater on both sides. - LayoutUnit prevLeft = block()->logicalLeftOffsetForLine(prevBottom, false); - LayoutUnit prevRight = block()->logicalRightOffsetForLine(prevBottom, false); - LayoutUnit newLeft = block()->logicalLeftOffsetForLine(selectionTop, false); - LayoutUnit newRight = block()->logicalRightOffsetForLine(selectionTop, false); + LayoutUnit prevLeft = block().logicalLeftOffsetForLine(prevBottom, false); + LayoutUnit prevRight = block().logicalRightOffsetForLine(prevBottom, false); + LayoutUnit newLeft = block().logicalLeftOffsetForLine(selectionTop, false); + LayoutUnit newRight = block().logicalRightOffsetForLine(selectionTop, false); if (prevLeft > newLeft || prevRight < newRight) return selectionTop; } @@ -546,12 +429,12 @@ LayoutUnit RootInlineBox::selectionTopAdjustedForPrecedingBlock() const { LayoutUnit top = selectionTop(); - RenderObject::SelectionState blockSelectionState = root()->block()->selectionState(); + 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 (RenderBlock* block = root().block().blockBeforeWithinSelectionRoot(offsetToBlockBefore)) { if (RootInlineBox* lastLine = block->lastRootBox()) { RenderObject::SelectionState lastLineSelectionState = lastLine->selectionState(); if (lastLineSelectionState != RenderObject::SelectionInside && lastLineSelectionState != RenderObject::SelectionStart) @@ -570,20 +453,20 @@ LayoutUnit RootInlineBox::selectionBottom() const LayoutUnit selectionBottom = m_lineBottom; if (m_hasAnnotationsAfter) - selectionBottom += !renderer()->style()->isFlippedLinesWritingMode() ? computeUnderAnnotationAdjustment(m_lineBottom) : computeOverAnnotationAdjustment(m_lineBottom); + selectionBottom += !renderer().style()->isFlippedLinesWritingMode() ? computeUnderAnnotationAdjustment(m_lineBottom) : computeOverAnnotationAdjustment(m_lineBottom); - if (!renderer()->style()->isFlippedLinesWritingMode() || !nextRootBox()) + if (!renderer().style()->isFlippedLinesWritingMode() || !nextRootBox()) return selectionBottom; LayoutUnit nextTop = nextRootBox()->selectionTop(); - if (nextTop > selectionBottom && block()->containsFloats()) { + if (nextTop > selectionBottom && block().containsFloats()) { // The next line has actually been moved further over, probably from a large line-height, but possibly because the // line was forced to clear floats. If so, let's check the offsets, and only be willing to use the next // line's top if the offsets are greater on both sides. - LayoutUnit nextLeft = block()->logicalLeftOffsetForLine(nextTop, false); - LayoutUnit nextRight = block()->logicalRightOffsetForLine(nextTop, false); - LayoutUnit newLeft = block()->logicalLeftOffsetForLine(selectionBottom, false); - LayoutUnit newRight = block()->logicalRightOffsetForLine(selectionBottom, false); + LayoutUnit nextLeft = block().logicalLeftOffsetForLine(nextTop, false); + LayoutUnit nextRight = block().logicalRightOffsetForLine(nextTop, false); + LayoutUnit newLeft = block().logicalLeftOffsetForLine(selectionBottom, false); + LayoutUnit newRight = block().logicalRightOffsetForLine(selectionBottom, false); if (nextLeft > newLeft || nextRight < newRight) return selectionBottom; } @@ -593,22 +476,22 @@ LayoutUnit RootInlineBox::selectionBottom() const int RootInlineBox::blockDirectionPointInLine() const { - return !block()->style()->isFlippedBlocksWritingMode() ? max(lineTop(), selectionTop()) : min(lineBottom(), selectionBottom()); + return !block().style()->isFlippedBlocksWritingMode() ? max(lineTop(), selectionTop()) : min(lineBottom(), selectionBottom()); } -RenderBlockFlow* RootInlineBox::block() const +RenderBlockFlow& RootInlineBox::block() const { return toRenderBlockFlow(renderer()); } static bool isEditableLeaf(InlineBox* leaf) { - return leaf && leaf->renderer() && leaf->renderer()->node() && leaf->renderer()->node()->rendererIsEditable(); + return leaf && leaf->renderer().node() && leaf->renderer().node()->rendererIsEditable(); } InlineBox* RootInlineBox::closestLeafChildForPoint(const IntPoint& pointInContents, bool onlyEditableLeaves) { - return closestLeafChildForLogicalLeftPosition(block()->isHorizontalWritingMode() ? pointInContents.x() : pointInContents.y(), onlyEditableLeaves); + return closestLeafChildForLogicalLeftPosition(block().isHorizontalWritingMode() ? pointInContents.x() : pointInContents.y(), onlyEditableLeaves); } InlineBox* RootInlineBox::closestLeafChildForLogicalLeftPosition(int leftPosition, bool onlyEditableLeaves) @@ -627,19 +510,19 @@ InlineBox* RootInlineBox::closestLeafChildForLogicalLeftPosition(int leftPositio return firstLeaf; // Avoid returning a list marker when possible. - if (leftPosition <= firstLeaf->logicalLeft() && !firstLeaf->renderer()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(firstLeaf))) + if (leftPosition <= firstLeaf->logicalLeft() && !firstLeaf->renderer().isListMarker() && (!onlyEditableLeaves || isEditableLeaf(firstLeaf))) // The leftPosition coordinate is less or equal to left edge of the firstLeaf. // Return it. return firstLeaf; - if (leftPosition >= lastLeaf->logicalRight() && !lastLeaf->renderer()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(lastLeaf))) + if (leftPosition >= lastLeaf->logicalRight() && !lastLeaf->renderer().isListMarker() && (!onlyEditableLeaves || isEditableLeaf(lastLeaf))) // The leftPosition coordinate is greater or equal to right edge of the lastLeaf. // Return it. return lastLeaf; InlineBox* closestLeaf = 0; for (InlineBox* leaf = firstLeaf; leaf; leaf = leaf->nextLeafChildIgnoringLineBreak()) { - if (!leaf->renderer()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(leaf))) { + if (!leaf->renderer().isListMarker() && (!onlyEditableLeaves || isEditableLeaf(leaf))) { closestLeaf = leaf; if (leftPosition < leaf->logicalRight()) // The x coordinate is less than the right edge of the box. @@ -682,17 +565,17 @@ EllipsisBox* RootInlineBox::ellipsisBox() const void RootInlineBox::removeLineBoxFromRenderObject() { - block()->lineBoxes()->removeLineBox(this); + block().lineBoxes()->removeLineBox(this); } void RootInlineBox::extractLineBoxFromRenderObject() { - block()->lineBoxes()->extractLineBox(this); + block().lineBoxes()->extractLineBox(this); } void RootInlineBox::attachLineBoxToRenderObject() { - block()->lineBoxes()->attachLineBox(this); + block().lineBoxes()->attachLineBox(this); } LayoutRect RootInlineBox::paddedLayoutOverflowRect(LayoutUnit endPadding) const @@ -735,8 +618,8 @@ 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(isFirstLineStyle())->lineBoxContain() & LineBoxContainReplaced) { + if (box->renderer().isReplaced()) { + if (renderer().style(isFirstLineStyle())->lineBoxContain() & LineBoxContainReplaced) { ascent = box->baselinePosition(baselineType()); descent = box->lineHeight() - ascent; @@ -761,8 +644,8 @@ void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallb bool setUsedFont = false; bool setUsedFontWithLeading = false; - if (usedFonts && !usedFonts->isEmpty() && (includeFont || (box->renderer()->style(isFirstLineStyle())->lineHeight().isNegative() && includeLeading))) { - usedFonts->append(box->renderer()->style(isFirstLineStyle())->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(); int usedFontAscent = fontMetrics.ascent(baselineType()); @@ -800,8 +683,8 @@ void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallb } if (includeFontForBox(box) && !setUsedFont) { - int fontAscent = box->renderer()->style(isFirstLineStyle())->fontMetrics().ascent(baselineType()); - int fontDescent = box->renderer()->style(isFirstLineStyle())->fontMetrics().descent(baselineType()); + int fontAscent = box->renderer().style(isFirstLineStyle())->fontMetrics().ascent(baselineType()); + int fontDescent = box->renderer().style(isFirstLineStyle())->fontMetrics().descent(baselineType()); setAscentAndDescent(ascent, descent, fontAscent, fontDescent, ascentDescentSet); affectsAscent = fontAscent - box->logicalTop() > 0; affectsDescent = fontDescent + box->logicalTop() > 0; @@ -811,14 +694,14 @@ 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(isFirstLineStyle())->fontMetrics().ascent(baselineType()))); - glyphOverflow->bottom = min(glyphOverflow->bottom, max(0, glyphOverflow->bottom - box->renderer()->style(isFirstLineStyle())->fontMetrics().descent(baselineType()))); + glyphOverflow->top = min(glyphOverflow->top, max(0, glyphOverflow->top - box->renderer().style(isFirstLineStyle())->fontMetrics().ascent(baselineType()))); + glyphOverflow->bottom = min(glyphOverflow->bottom, max(0, glyphOverflow->bottom - box->renderer().style(isFirstLineStyle())->fontMetrics().descent(baselineType()))); } if (includeMarginForBox(box)) { - LayoutUnit ascentWithMargin = box->renderer()->style(isFirstLineStyle())->fontMetrics().ascent(baselineType()); - LayoutUnit descentWithMargin = box->renderer()->style(isFirstLineStyle())->fontMetrics().descent(baselineType()); - if (box->parent() && !box->renderer()->isText()) { + LayoutUnit ascentWithMargin = box->renderer().style(isFirstLineStyle())->fontMetrics().ascent(baselineType()); + LayoutUnit descentWithMargin = box->renderer().style(isFirstLineStyle())->fontMetrics().descent(baselineType()); + 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(); } @@ -832,7 +715,7 @@ void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallb LayoutUnit RootInlineBox::verticalPositionForBox(InlineBox* box, VerticalPositionCache& verticalPositionCache) { - if (box->renderer()->isText()) + if (box->renderer().isText()) return box->parent()->logicalTop(); RenderBoxModelObject* renderer = box->boxModelObject(); @@ -865,7 +748,7 @@ LayoutUnit RootInlineBox::verticalPositionForBox(InlineBox* box, VerticalPositio if (verticalAlign != BASELINE) { const Font& font = parent->style(firstLine)->font(); const FontMetrics& fontMetrics = font.fontMetrics(); - int fontSize = font.pixelSize(); + int fontSize = font.fontDescription().computedPixelSize(); LineDirectionMode lineDirection = parent->isHorizontalWritingMode() ? HorizontalLine : VerticalLine; @@ -891,7 +774,7 @@ LayoutUnit RootInlineBox::verticalPositionForBox(InlineBox* box, VerticalPositio lineHeight = renderer->style()->computedLineHeight(); else lineHeight = renderer->lineHeight(firstLine, lineDirection); - verticalPosition -= valueForLength(renderer->style()->verticalAlignLength(), lineHeight, renderer->view()); + verticalPosition -= valueForLength(renderer->style()->verticalAlignLength(), lineHeight); } } @@ -904,45 +787,45 @@ LayoutUnit RootInlineBox::verticalPositionForBox(InlineBox* box, VerticalPositio bool RootInlineBox::includeLeadingForBox(InlineBox* box) const { - if (box->renderer()->isReplaced() || (box->renderer()->isText() && !box->isText())) + if (box->renderer().isReplaced() || (box->renderer().isText() && !box->isText())) return false; - LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain(); + LineBoxContain lineBoxContain = renderer().style()->lineBoxContain(); return (lineBoxContain & LineBoxContainInline) || (box == this && (lineBoxContain & LineBoxContainBlock)); } bool RootInlineBox::includeFontForBox(InlineBox* box) const { - if (box->renderer()->isReplaced() || (box->renderer()->isText() && !box->isText())) + if (box->renderer().isReplaced() || (box->renderer().isText() && !box->isText())) return false; if (!box->isText() && box->isInlineFlowBox() && !toInlineFlowBox(box)->hasTextChildren()) return false; // For now map "glyphs" to "font" in vertical text mode until the bounds returned by glyphs aren't garbage. - LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain(); + LineBoxContain lineBoxContain = renderer().style()->lineBoxContain(); return (lineBoxContain & LineBoxContainFont) || (!isHorizontal() && (lineBoxContain & LineBoxContainGlyphs)); } bool RootInlineBox::includeGlyphsForBox(InlineBox* box) const { - if (box->renderer()->isReplaced() || (box->renderer()->isText() && !box->isText())) + if (box->renderer().isReplaced() || (box->renderer().isText() && !box->isText())) return false; if (!box->isText() && box->isInlineFlowBox() && !toInlineFlowBox(box)->hasTextChildren()) return false; // FIXME: We can't fit to glyphs yet for vertical text, since the bounds returned are garbage. - LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain(); + LineBoxContain lineBoxContain = renderer().style()->lineBoxContain(); return isHorizontal() && (lineBoxContain & LineBoxContainGlyphs); } bool RootInlineBox::includeMarginForBox(InlineBox* box) const { - if (box->renderer()->isReplaced() || (box->renderer()->isText() && !box->isText())) + if (box->renderer().isReplaced() || (box->renderer().isText() && !box->isText())) return false; - LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain(); + LineBoxContain lineBoxContain = renderer().style()->lineBoxContain(); return lineBoxContain & LineBoxContainInlineBox; } @@ -950,13 +833,13 @@ bool RootInlineBox::includeMarginForBox(InlineBox* box) const bool RootInlineBox::fitsToGlyphs() const { // FIXME: We can't fit to glyphs yet for vertical text, since the bounds returned are garbage. - LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain(); + LineBoxContain lineBoxContain = renderer().style()->lineBoxContain(); return isHorizontal() && (lineBoxContain & LineBoxContainGlyphs); } bool RootInlineBox::includesRootLineBoxFontOrLeading() const { - LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain(); + LineBoxContain lineBoxContain = renderer().style()->lineBoxContain(); return (lineBoxContain & LineBoxContainBlock) || (lineBoxContain & LineBoxContainInline) || (lineBoxContain & LineBoxContainFont); } @@ -965,9 +848,9 @@ Node* RootInlineBox::getLogicalStartBoxWithNode(InlineBox*& startBox) const Vector<InlineBox*> leafBoxesInLogicalOrder; collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder); for (size_t i = 0; i < leafBoxesInLogicalOrder.size(); ++i) { - if (leafBoxesInLogicalOrder[i]->renderer()->node()) { + if (leafBoxesInLogicalOrder[i]->renderer().node()) { startBox = leafBoxesInLogicalOrder[i]; - return startBox->renderer()->node(); + return startBox->renderer().node(); } } startBox = 0; @@ -979,9 +862,9 @@ Node* RootInlineBox::getLogicalEndBoxWithNode(InlineBox*& endBox) const Vector<InlineBox*> leafBoxesInLogicalOrder; collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder); for (size_t i = leafBoxesInLogicalOrder.size(); i > 0; --i) { - if (leafBoxesInLogicalOrder[i - 1]->renderer()->node()) { + if (leafBoxesInLogicalOrder[i - 1]->renderer().node()) { endBox = leafBoxesInLogicalOrder[i - 1]; - return endBox->renderer()->node(); + return endBox->renderer().node(); } } endBox = 0; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RootInlineBox.h b/chromium/third_party/WebKit/Source/core/rendering/RootInlineBox.h index 7dfde5faf5b..32b1c55221d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RootInlineBox.h +++ b/chromium/third_party/WebKit/Source/core/rendering/RootInlineBox.h @@ -29,14 +29,13 @@ namespace WebCore { class EllipsisBox; class HitTestResult; class RenderBlockFlow; -class RenderRegion; struct BidiStatus; struct GapRects; class RootInlineBox : public InlineFlowBox { public: - explicit RootInlineBox(RenderBlockFlow*); + explicit RootInlineBox(RenderBlockFlow&); virtual void destroy() OVERRIDE FINAL; @@ -64,9 +63,6 @@ public: LayoutUnit paginatedLineWidth() const { return m_fragmentationData ? m_fragmentationData->m_paginatedLineWidth : LayoutUnit(0); } void setPaginatedLineWidth(LayoutUnit width) { ensureLineFragmentationData()->m_paginatedLineWidth = width; } - RenderRegion* containingRegion() const; - void setContainingRegion(RenderRegion*); - LayoutUnit selectionTop() const; LayoutUnit selectionBottom() const; LayoutUnit selectionHeight() const { return max<LayoutUnit>(0, selectionBottom() - selectionTop()); } @@ -117,7 +113,7 @@ public: virtual int baselinePosition(FontBaseline baselineType) const OVERRIDE FINAL; virtual LayoutUnit lineHeight() const OVERRIDE FINAL; - virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); + virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE FINAL; using InlineBox::hasSelectedChildren; @@ -129,7 +125,7 @@ public: GapRects lineSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, LayoutUnit selTop, LayoutUnit selHeight, const PaintInfo*); - RenderBlockFlow* block() const; + RenderBlockFlow& block() const; InlineBox* closestLeafChildForPoint(const IntPoint&, bool onlyEditableLeaves); InlineBox* closestLeafChildForLogicalLeftPosition(int, bool onlyEditableLeaves = false); @@ -189,11 +185,9 @@ public: Node* getLogicalEndBoxWithNode(InlineBox*&) const; #ifndef NDEBUG - virtual const char* boxName() const; + virtual const char* boxName() const OVERRIDE; #endif private: - LayoutUnit lineSnapAdjustment(LayoutUnit delta = 0) const; - LayoutUnit beforeAnnotationsAdjustment() const; struct LineFragmentationData; @@ -223,17 +217,13 @@ private: WTF_MAKE_NONCOPYABLE(LineFragmentationData); WTF_MAKE_FAST_ALLOCATED; public: LineFragmentationData() - : m_containingRegion(0) - , m_paginationStrut(0) + : m_paginationStrut(0) , m_paginatedLineWidth(0) , m_isFirstAfterPageBreak(false) { } - // It should not be assumed the |containingRegion| is always valid. - // It can also be 0 if the flow has no region chain. - RenderRegion* m_containingRegion; LayoutUnit m_paginationStrut; LayoutUnit m_paginatedLineWidth; bool m_isFirstAfterPageBreak; diff --git a/chromium/third_party/WebKit/Source/core/rendering/ScrollBehavior.cpp b/chromium/third_party/WebKit/Source/core/rendering/ScrollAlignment.cpp index d331f1dc07b..433a0864815 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/ScrollBehavior.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/ScrollAlignment.cpp @@ -42,24 +42,24 @@ */ #include "config.h" -#include "core/rendering/ScrollBehavior.h" +#include "core/rendering/ScrollAlignment.h" #include "platform/geometry/LayoutRect.h" namespace WebCore { -const ScrollAlignment ScrollAlignment::alignCenterIfNeeded = { noScroll, alignCenter, alignToClosestEdge }; -const ScrollAlignment ScrollAlignment::alignToEdgeIfNeeded = { noScroll, alignToClosestEdge, alignToClosestEdge }; -const ScrollAlignment ScrollAlignment::alignCenterAlways = { alignCenter, alignCenter, alignCenter }; -const ScrollAlignment ScrollAlignment::alignTopAlways = { alignTop, alignTop, alignTop }; -const ScrollAlignment ScrollAlignment::alignBottomAlways = { alignBottom, alignBottom, alignBottom }; +const ScrollAlignment ScrollAlignment::alignCenterIfNeeded = { ScrollAlignmentNoScroll, ScrollAlignmentCenter, ScrollAlignmentClosestEdge }; +const ScrollAlignment ScrollAlignment::alignToEdgeIfNeeded = { ScrollAlignmentNoScroll, ScrollAlignmentClosestEdge, ScrollAlignmentClosestEdge }; +const ScrollAlignment ScrollAlignment::alignCenterAlways = { ScrollAlignmentCenter, ScrollAlignmentCenter, ScrollAlignmentCenter }; +const ScrollAlignment ScrollAlignment::alignTopAlways = { ScrollAlignmentTop, ScrollAlignmentTop, ScrollAlignmentTop }; +const ScrollAlignment ScrollAlignment::alignBottomAlways = { ScrollAlignmentBottom, ScrollAlignmentBottom, ScrollAlignmentBottom }; #define MIN_INTERSECT_FOR_REVEAL 32 LayoutRect ScrollAlignment::getRectToExpose(const LayoutRect& visibleRect, const LayoutRect& exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY) { // Determine the appropriate X behavior. - ScrollBehavior scrollX; + ScrollAlignmentBehavior scrollX; LayoutRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height()); LayoutUnit intersectWidth = intersection(visibleRect, exposeRectX).width(); if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL) { @@ -70,8 +70,8 @@ LayoutRect ScrollAlignment::getRectToExpose(const LayoutRect& visibleRect, const } else if (intersectWidth == visibleRect.width()) { // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work. scrollX = getVisibleBehavior(alignX); - if (scrollX == alignCenter) - scrollX = noScroll; + if (scrollX == ScrollAlignmentCenter) + scrollX = ScrollAlignmentNoScroll; } else if (intersectWidth > 0) { // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior scrollX = getPartialBehavior(alignX); @@ -79,29 +79,29 @@ LayoutRect ScrollAlignment::getRectToExpose(const LayoutRect& visibleRect, const scrollX = getHiddenBehavior(alignX); } - if (scrollX == alignToClosestEdge) { + if (scrollX == ScrollAlignmentClosestEdge) { // Closest edge is the right in two cases: // (1) exposeRect to the right of and smaller than visibleRect // (2) exposeRect to the left of and larger than visibleRect if ((exposeRect.maxX() > visibleRect.maxX() && exposeRect.width() < visibleRect.width()) || (exposeRect.maxX() < visibleRect.maxX() && exposeRect.width() > visibleRect.width())) { - scrollX = alignRight; + scrollX = ScrollAlignmentRight; } } // Given the X behavior, compute the X coordinate. LayoutUnit x; - if (scrollX == noScroll) + if (scrollX == ScrollAlignmentNoScroll) x = visibleRect.x(); - else if (scrollX == alignRight) + else if (scrollX == ScrollAlignmentRight) x = exposeRect.maxX() - visibleRect.width(); - else if (scrollX == alignCenter) + else if (scrollX == ScrollAlignmentCenter) x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2; else x = exposeRect.x(); // Determine the appropriate Y behavior. - ScrollBehavior scrollY; + ScrollAlignmentBehavior scrollY; LayoutRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height()); LayoutUnit intersectHeight = intersection(visibleRect, exposeRectY).height(); if (intersectHeight == exposeRect.height()) { @@ -110,8 +110,8 @@ LayoutRect ScrollAlignment::getRectToExpose(const LayoutRect& visibleRect, const } else if (intersectHeight == visibleRect.height()) { // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work. scrollY = getVisibleBehavior(alignY); - if (scrollY == alignCenter) - scrollY = noScroll; + if (scrollY == ScrollAlignmentCenter) + scrollY = ScrollAlignmentNoScroll; } else if (intersectHeight > 0) { // If the rectangle is partially visible, use the specified partial behavior scrollY = getPartialBehavior(alignY); @@ -119,23 +119,23 @@ LayoutRect ScrollAlignment::getRectToExpose(const LayoutRect& visibleRect, const scrollY = getHiddenBehavior(alignY); } - if (scrollY == alignToClosestEdge) { + if (scrollY == ScrollAlignmentClosestEdge) { // Closest edge is the bottom in two cases: // (1) exposeRect below and smaller than visibleRect // (2) exposeRect above and larger than visibleRect if ((exposeRect.maxY() > visibleRect.maxY() && exposeRect.height() < visibleRect.height()) || (exposeRect.maxY() < visibleRect.maxY() && exposeRect.height() > visibleRect.height())) { - scrollY = alignBottom; + scrollY = ScrollAlignmentBottom; } } // Given the Y behavior, compute the Y coordinate. LayoutUnit y; - if (scrollY == noScroll) + if (scrollY == ScrollAlignmentNoScroll) y = visibleRect.y(); - else if (scrollY == alignBottom) + else if (scrollY == ScrollAlignmentBottom) y = exposeRect.maxY() - visibleRect.height(); - else if (scrollY == alignCenter) + else if (scrollY == ScrollAlignmentCenter) y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2; else y = exposeRect.y(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/ScrollBehavior.h b/chromium/third_party/WebKit/Source/core/rendering/ScrollAlignment.h index 7c683d874a0..f22b1d9d6a8 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/ScrollBehavior.h +++ b/chromium/third_party/WebKit/Source/core/rendering/ScrollAlignment.h @@ -41,27 +41,27 @@ * version of this file under any of the LGPL, the MPL or the GPL. */ -#ifndef ScrollBehavior_h -#define ScrollBehavior_h +#ifndef ScrollAlignment_h +#define ScrollAlignment_h namespace WebCore { -enum ScrollBehavior { - noScroll, - alignCenter, - alignTop, - alignBottom, - alignLeft, - alignRight, - alignToClosestEdge +enum ScrollAlignmentBehavior { + ScrollAlignmentNoScroll, + ScrollAlignmentCenter, + ScrollAlignmentTop, + ScrollAlignmentBottom, + ScrollAlignmentLeft, + ScrollAlignmentRight, + ScrollAlignmentClosestEdge }; class LayoutRect; struct ScrollAlignment { - static ScrollBehavior getVisibleBehavior(const ScrollAlignment& s) { return s.m_rectVisible; } - static ScrollBehavior getPartialBehavior(const ScrollAlignment& s) { return s.m_rectPartial; } - static ScrollBehavior getHiddenBehavior(const ScrollAlignment& s) { return s.m_rectHidden; } + static ScrollAlignmentBehavior getVisibleBehavior(const ScrollAlignment& s) { return s.m_rectVisible; } + static ScrollAlignmentBehavior getPartialBehavior(const ScrollAlignment& s) { return s.m_rectPartial; } + static ScrollAlignmentBehavior getHiddenBehavior(const ScrollAlignment& s) { return s.m_rectHidden; } // FIXME: This function should probably go somewhere else but where? static LayoutRect getRectToExpose(const LayoutRect& visibleRect, const LayoutRect& exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY); @@ -72,12 +72,12 @@ struct ScrollAlignment { static const ScrollAlignment alignTopAlways; static const ScrollAlignment alignBottomAlways; - ScrollBehavior m_rectVisible; - ScrollBehavior m_rectHidden; - ScrollBehavior m_rectPartial; + ScrollAlignmentBehavior m_rectVisible; + ScrollAlignmentBehavior m_rectHidden; + ScrollAlignmentBehavior m_rectPartial; }; }; // namespace WebCore -#endif // ScrollBehavior_h +#endif // ScrollAlignment_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/SubtreeLayoutScope.cpp b/chromium/third_party/WebKit/Source/core/rendering/SubtreeLayoutScope.cpp index d650513a1c8..a5793a69e9a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/SubtreeLayoutScope.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/SubtreeLayoutScope.cpp @@ -36,21 +36,15 @@ namespace WebCore { -SubtreeLayoutScope::SubtreeLayoutScope(RenderObject* root) +SubtreeLayoutScope::SubtreeLayoutScope(RenderObject& root) : m_root(root) { - RELEASE_ASSERT(m_root->document().view()->isInLayout()); + RELEASE_ASSERT(m_root.document().view()->isInPerformLayout()); } SubtreeLayoutScope::~SubtreeLayoutScope() { - // Partial layout early-exits layout and will leave the tree as needing layout. - if (m_root->frameView()->partialLayout().isStopping()) { - ASSERT(m_root->needsLayout()); - return; - } - - RELEASE_ASSERT(!m_root->needsLayout()); + RELEASE_ASSERT(!m_root.needsLayout()); #ifndef NDEBUG for (HashSet<RenderObject*>::iterator it = m_renderersToLayout.begin(); it != m_renderersToLayout.end(); ++it) @@ -60,13 +54,13 @@ SubtreeLayoutScope::~SubtreeLayoutScope() void SubtreeLayoutScope::setNeedsLayout(RenderObject* descendant) { - ASSERT(descendant->isDescendantOf(m_root)); - descendant->setNeedsLayout(MarkContainingBlockChain, this); + ASSERT(descendant->isDescendantOf(&m_root)); + descendant->setNeedsLayoutAndFullPaintInvalidation(MarkContainingBlockChain, this); } void SubtreeLayoutScope::setChildNeedsLayout(RenderObject* descendant) { - ASSERT(descendant->isDescendantOf(m_root)); + ASSERT(descendant->isDescendantOf(&m_root)); descendant->setChildNeedsLayout(MarkContainingBlockChain, this); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/SubtreeLayoutScope.h b/chromium/third_party/WebKit/Source/core/rendering/SubtreeLayoutScope.h index c073b7f4cf1..fc9219ff5da 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/SubtreeLayoutScope.h +++ b/chromium/third_party/WebKit/Source/core/rendering/SubtreeLayoutScope.h @@ -48,17 +48,17 @@ class RenderObject; class SubtreeLayoutScope { public: - SubtreeLayoutScope(RenderObject* root); + SubtreeLayoutScope(RenderObject& root); ~SubtreeLayoutScope(); void setNeedsLayout(RenderObject* descendant); void setChildNeedsLayout(RenderObject* descendant); - RenderObject* root() { return m_root; } + RenderObject& root() { return m_root; } void addRendererToLayout(RenderObject* renderer); private: - RenderObject* m_root; + RenderObject& m_root; #ifndef NDEBUG HashSet<RenderObject*> m_renderersToLayout; diff --git a/chromium/third_party/WebKit/Source/core/rendering/TextAutosizer.cpp b/chromium/third_party/WebKit/Source/core/rendering/TextAutosizer.cpp index bc57d66cfab..290c008fa79 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/TextAutosizer.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/TextAutosizer.cpp @@ -24,9 +24,11 @@ #include <algorithm> #include "core/dom/Document.h" -#include "core/html/HTMLElement.h" -#include "core/inspector/InspectorInstrumentation.h" +#include "core/frame/LocalFrame.h" #include "core/frame/Settings.h" +#include "core/frame/UseCounter.h" +#include "core/html/HTMLElement.h" +#include "core/page/Page.h" #include "core/rendering/RenderListItem.h" #include "core/rendering/RenderObject.h" #include "core/rendering/RenderText.h" @@ -36,10 +38,11 @@ #include "platform/TraceEvent.h" #include "platform/geometry/IntSize.h" #include "wtf/StdLibExtras.h" -#include "wtf/Vector.h" namespace WebCore { +#define AUTOSIZING_CLUSTER_HASH + using namespace HTMLNames; struct TextAutosizingWindowInfo { @@ -47,26 +50,25 @@ struct TextAutosizingWindowInfo { IntSize minLayoutSize; }; -// Represents cluster related data. Instances should not persist between calls to processSubtree. -struct TextAutosizingClusterInfo { - explicit TextAutosizingClusterInfo(RenderBlock* root) - : root(root) - , blockContainingAllText(0) - , maxAllowedDifferenceFromTextWidth(150) +// Represents a POD of a selection of fields for hashing. The fields are selected to detect similar +// nodes in the Render Tree from the viewpoint of text autosizing. +struct RenderObjectPodForHash { + RenderObjectPodForHash() + : qualifiedNameHash(0) + , packedStyleProperties(0) + , width(0) { } + ~RenderObjectPodForHash() { } - RenderBlock* root; - const RenderBlock* blockContainingAllText; + unsigned qualifiedNameHash; - // Upper limit on the difference between the width of the cluster's block containing all - // text and that of a narrow child before the child becomes a separate cluster. - float maxAllowedDifferenceFromTextWidth; - - // Descendants of the cluster that are narrower than the block containing all text and must be - // processed together. - Vector<TextAutosizingClusterInfo> narrowDescendants; + // Style specific selection of signals + unsigned packedStyleProperties; + float width; }; +// To allow for efficient hashing using StringHasher. +COMPILE_ASSERT(!(sizeof(RenderObjectPodForHash) % sizeof(UChar)), RenderObjectPodForHashMultipleOfUchar); #ifdef AUTOSIZING_DOM_DEBUG_INFO static void writeDebugInfo(RenderObject* renderObject, const AtomicString& output) @@ -104,48 +106,115 @@ static RenderObject* getAncestorList(const RenderObject* renderer) // see http://www.whatwg.org/specs/web-apps/current-work/multipage/grouping-content.html#the-li-element for (RenderObject* ancestor = renderer->parent(); ancestor; ancestor = ancestor->parent()) { Node* parentNode = ancestor->generatingNode(); - if (parentNode && (parentNode->hasTagName(olTag) || parentNode->hasTagName(ulTag))) + if (parentNode && (isHTMLOListElement(*parentNode) || isHTMLUListElement(*parentNode))) return ancestor; } return 0; } +static Node* getGeneratingElementNode(const RenderObject* renderer) +{ + Node* node = renderer->generatingNode(); + return (node && node->isElementNode()) ? node : 0; +} + +static unsigned hashMemory(const void* data, size_t length) +{ + return StringHasher::computeHash<UChar>(static_cast<const UChar*>(data), length / sizeof(UChar)); +} + +static unsigned computeLocalHash(const RenderObject* renderer) +{ + Node* generatingElementNode = getGeneratingElementNode(renderer); + ASSERT(generatingElementNode); + + RenderObjectPodForHash podForHash; + podForHash.qualifiedNameHash = QualifiedNameHash::hash(toElement(generatingElementNode)->tagQName()); + + if (RenderStyle* style = renderer->style()) { + podForHash.packedStyleProperties = style->direction(); + podForHash.packedStyleProperties |= (style->position() << 1); + podForHash.packedStyleProperties |= (style->floating() << 4); + podForHash.packedStyleProperties |= (style->display() << 6); + podForHash.packedStyleProperties |= (style->width().type() << 11); + // packedStyleProperties effectively using 15 bits now. + + // consider for adding: writing mode, padding. + + podForHash.width = style->width().getFloatValue(); + } + + return hashMemory(&podForHash, sizeof(podForHash)); +} + TextAutosizer::TextAutosizer(Document* document) : m_document(document) + , m_previouslyAutosized(false) +{ +} + +unsigned TextAutosizer::getCachedHash(const RenderObject* renderer, bool putInCacheIfAbsent) { + HashMap<const RenderObject*, unsigned>::const_iterator it = m_hashCache.find(renderer); + if (it != m_hashCache.end()) + return it->value; + + RenderObject* rendererParent = renderer->parent(); + while (rendererParent && !getGeneratingElementNode(rendererParent)) + rendererParent = rendererParent->parent(); + + const unsigned parentHashValue = rendererParent ? getCachedHash(rendererParent, true) : 0; + const unsigned hashes[2] = { parentHashValue, computeLocalHash(renderer) }; + const unsigned combinedHashValue = hashMemory(hashes, sizeof(hashes)); + if (putInCacheIfAbsent) + m_hashCache.add(renderer, combinedHashValue); + return combinedHashValue; +} + +bool TextAutosizer::isApplicable() const +{ + return m_document->settings() + && m_document->settings()->textAutosizingEnabled() + && m_document->page() + && m_document->page()->mainFrame() + && m_document->page()->deprecatedLocalMainFrame()->loader().stateMachine()->committedFirstRealDocumentLoad(); } void TextAutosizer::recalculateMultipliers() { - RenderObject* renderer = m_document->renderer(); + if (!isApplicable() && !m_previouslyAutosized) + return; + + RenderObject* renderer = m_document->renderView(); while (renderer) { if (renderer->style() && renderer->style()->textAutosizingMultiplier() != 1) setMultiplier(renderer, 1); renderer = renderer->nextInPreOrder(); } + m_previouslyAutosized = false; } bool TextAutosizer::processSubtree(RenderObject* layoutRoot) { - TRACE_EVENT0("webkit", "TextAutosizer::processSubtree"); + TRACE_EVENT0("webkit", "TextAutosizer: check if needed"); - if (!m_document->settings() || !m_document->settings()->textAutosizingEnabled() || layoutRoot->view()->document().printing() || !m_document->page()) + if (!isApplicable() || layoutRoot->view()->document().printing()) return false; - Frame* mainFrame = m_document->page()->mainFrame(); - + LocalFrame* mainFrame = m_document->page()->deprecatedLocalMainFrame(); TextAutosizingWindowInfo windowInfo; // Window area, in logical (density-independent) pixels. windowInfo.windowSize = m_document->settings()->textAutosizingWindowSizeOverride(); if (windowInfo.windowSize.isEmpty()) - windowInfo.windowSize = mainFrame->view()->unscaledVisibleContentSize(ScrollableArea::IncludeScrollbars); + windowInfo.windowSize = mainFrame->view()->unscaledVisibleContentSize(IncludeScrollbars); // Largest area of block that can be visible at once (assuming the main // frame doesn't get scaled to less than overview scale), in CSS pixels. windowInfo.minLayoutSize = mainFrame->view()->layoutSize(); - for (Frame* frame = m_document->frame(); frame; frame = frame->tree().parent()) - windowInfo.minLayoutSize = windowInfo.minLayoutSize.shrunkTo(frame->view()->layoutSize()); + for (Frame* frame = m_document->frame(); frame; frame = frame->tree().parent()) { + windowInfo.minLayoutSize = windowInfo.minLayoutSize.shrunkTo(toLocalFrame(frame)->view()->layoutSize()); + } // The layoutRoot could be neither a container nor a cluster, so walk up the tree till we find each of these. RenderBlock* container = layoutRoot->isRenderBlock() ? toRenderBlock(layoutRoot) : layoutRoot->containingBlock(); @@ -163,9 +232,21 @@ bool TextAutosizer::processSubtree(RenderObject* layoutRoot) std::numeric_limits<float>::infinity()) == 1.0f) return false; + TRACE_EVENT0("webkit", "TextAutosizer: process root cluster"); + UseCounter::count(*m_document, UseCounter::TextAutosizing); + TextAutosizingClusterInfo clusterInfo(cluster); processCluster(clusterInfo, container, layoutRoot, windowInfo); - InspectorInstrumentation::didAutosizeText(layoutRoot); + +#ifdef AUTOSIZING_CLUSTER_HASH + // Second pass to autosize stale non-autosized clusters for consistency. + secondPassProcessStaleNonAutosizedClusters(); + m_hashCache.clear(); + m_hashToMultiplier.clear(); + m_hashesToAutosizeSecondPass.clear(); + m_nonAutosizedClusters.clear(); +#endif + m_previouslyAutosized = true; return true; } @@ -180,9 +261,10 @@ float TextAutosizer::clusterMultiplier(WritingMode writingMode, const TextAutosi multiplier *= m_document->settings()->accessibilityFontScaleFactor(); // If the page has a meta viewport or @viewport, don't apply the device scale adjustment. - const ViewportDescription& viewportDescription = m_document->page()->mainFrame()->document()->viewportDescription(); + const ViewportDescription& viewportDescription = m_document->page()->deprecatedLocalMainFrame()->document()->viewportDescription(); if (!viewportDescription.isSpecifiedByAuthor()) { - multiplier *= m_document->settings()->deviceScaleAdjustment(); + float deviceScaleAdjustment = m_document->settings()->deviceScaleAdjustment(); + multiplier *= deviceScaleAdjustment; } return std::max(1.0f, multiplier); } @@ -191,7 +273,7 @@ void TextAutosizer::processClusterInternal(TextAutosizingClusterInfo& clusterInf { processContainer(multiplier, container, clusterInfo, subtreeRoot, windowInfo); #ifdef AUTOSIZING_DOM_DEBUG_INFO - writeDebugInfo(clusterInfo.root, String::format("cluster:%f", multiplier)); + writeDebugInfo(clusterInfo.root, AtomicString(String::format("cluster:%f", multiplier))); #endif Vector<Vector<TextAutosizingClusterInfo> > narrowDescendantsGroups; @@ -200,6 +282,58 @@ void TextAutosizer::processClusterInternal(TextAutosizingClusterInfo& clusterInf processCompositeCluster(narrowDescendantsGroups[i], windowInfo); } +unsigned TextAutosizer::computeCompositeClusterHash(Vector<TextAutosizingClusterInfo>& clusterInfos) +{ + if (clusterInfos.size() == 1 && getGeneratingElementNode(clusterInfos[0].root)) + return getCachedHash(clusterInfos[0].root, false); + + // FIXME: consider hashing clusters for which clusterInfos.size() > 1 + return 0; +} + +void TextAutosizer::addNonAutosizedCluster(unsigned key, TextAutosizingClusterInfo& value) +{ + HashMap<unsigned, OwnPtr<Vector<TextAutosizingClusterInfo> > >::const_iterator it = m_nonAutosizedClusters.find(key); + if (it == m_nonAutosizedClusters.end()) { + m_nonAutosizedClusters.add(key, adoptPtr(new Vector<TextAutosizingClusterInfo>(1, value))); + return; + } + it->value->append(value); +} + +float TextAutosizer::computeMultiplier(Vector<TextAutosizingClusterInfo>& clusterInfos, const TextAutosizingWindowInfo& windowInfo, float textWidth) +{ +#ifdef AUTOSIZING_CLUSTER_HASH + // When hashing is enabled this function returns a multiplier based on previously seen clusters. + // It will return a non-unit multiplier if a cluster with the same hash value has been previously + // autosized. + unsigned clusterHash = computeCompositeClusterHash(clusterInfos); +#else + unsigned clusterHash = 0; +#endif + + if (clusterHash) { + HashMap<unsigned, float>::iterator it = m_hashToMultiplier.find(clusterHash); + if (it != m_hashToMultiplier.end()) + return it->value; + } + + if (compositeClusterShouldBeAutosized(clusterInfos, textWidth)) { + float multiplier = clusterMultiplier(clusterInfos[0].root->style()->writingMode(), windowInfo, textWidth); + if (clusterHash) { + if (multiplier > 1 && m_nonAutosizedClusters.contains(clusterHash)) + m_hashesToAutosizeSecondPass.append(clusterHash); + m_hashToMultiplier.add(clusterHash, multiplier); + } + return multiplier; + } + + if (clusterHash) + addNonAutosizedCluster(clusterHash, clusterInfos[0]); + + return 1.0f; +} + void TextAutosizer::processCluster(TextAutosizingClusterInfo& clusterInfo, RenderBlock* container, RenderObject* subtreeRoot, const TextAutosizingWindowInfo& windowInfo) { // Many pages set a max-width on their content. So especially for the RenderView, instead of @@ -207,10 +341,11 @@ void TextAutosizer::processCluster(TextAutosizingClusterInfo& clusterInfo, Rende // descendant text node of the cluster (i.e. the deepest wrapper block that contains all the // text), and use its width instead. clusterInfo.blockContainingAllText = findDeepestBlockContainingAllText(clusterInfo.root); - float textWidth = clusterInfo.blockContainingAllText->contentLogicalWidth(); - float multiplier = 1.0; - if (clusterShouldBeAutosized(clusterInfo, textWidth)) - multiplier = clusterMultiplier(clusterInfo.root->style()->writingMode(), windowInfo, textWidth); + float textWidth = clusterInfo.blockContainingAllText->contentLogicalWidth().toFloat(); + + Vector<TextAutosizingClusterInfo> clusterInfos(1, clusterInfo); + float multiplier = computeMultiplier(clusterInfos, windowInfo, textWidth); + processClusterInternal(clusterInfo, container, subtreeRoot, windowInfo, multiplier); } @@ -223,18 +358,52 @@ void TextAutosizer::processCompositeCluster(Vector<TextAutosizingClusterInfo>& c for (size_t i = 0; i < clusterInfos.size(); ++i) { TextAutosizingClusterInfo& clusterInfo = clusterInfos[i]; clusterInfo.blockContainingAllText = findDeepestBlockContainingAllText(clusterInfo.root); - maxTextWidth = max<float>(maxTextWidth, clusterInfo.blockContainingAllText->contentLogicalWidth()); + maxTextWidth = max<float>(maxTextWidth, clusterInfo.blockContainingAllText->contentLogicalWidth().toFloat()); } - float multiplier = 1.0; - if (compositeClusterShouldBeAutosized(clusterInfos, maxTextWidth)) - multiplier = clusterMultiplier(clusterInfos[0].root->style()->writingMode(), windowInfo, maxTextWidth); + float multiplier = computeMultiplier(clusterInfos, windowInfo, maxTextWidth); for (size_t i = 0; i < clusterInfos.size(); ++i) { ASSERT(clusterInfos[i].root->style()->writingMode() == clusterInfos[0].root->style()->writingMode()); processClusterInternal(clusterInfos[i], clusterInfos[i].root, clusterInfos[i].root, windowInfo, multiplier); } } +void TextAutosizer::secondPassProcessStaleNonAutosizedClusters() +{ + for (size_t i = 0; i < m_hashesToAutosizeSecondPass.size(); ++i) { + unsigned hash = m_hashesToAutosizeSecondPass[i]; + float multiplier = m_hashToMultiplier.get(hash); + Vector<TextAutosizingClusterInfo>* val = m_nonAutosizedClusters.get(hash); + for (Vector<TextAutosizingClusterInfo>::iterator it2 = val->begin(); it2 != val->end(); ++it2) + processStaleContainer(multiplier, (*it2).root, *it2); + } +} + +void TextAutosizer::processStaleContainer(float multiplier, RenderBlock* cluster, TextAutosizingClusterInfo& clusterInfo) +{ + ASSERT(isAutosizingContainer(cluster)); + + // This method is different from processContainer() mainly in that it does not recurse into sub-clusters. + // Multiplier updates are restricted to the specified cluster only. Also the multiplier > 1 by construction + // of m_hashesToAutosizeSecondPass, so we don't need to check it explicitly. + float localMultiplier = containerShouldBeAutosized(cluster) ? multiplier : 1; + + RenderObject* descendant = nextInPreOrderSkippingDescendantsOfContainers(cluster, cluster); + while (descendant) { + if (descendant->isText()) { + if (localMultiplier != 1 && descendant->style()->textAutosizingMultiplier() == 1) { + setMultiplier(descendant, localMultiplier); + setMultiplier(descendant->parent(), localMultiplier); // Parent does line spacing. + } + } else if (isAutosizingContainer(descendant)) { + RenderBlock* descendantBlock = toRenderBlock(descendant); + if (!isAutosizingCluster(descendantBlock, clusterInfo)) + processStaleContainer(multiplier, descendantBlock, clusterInfo); + } + descendant = nextInPreOrderSkippingDescendantsOfContainers(descendant, cluster); + } +} + void TextAutosizer::processContainer(float multiplier, RenderBlock* container, TextAutosizingClusterInfo& clusterInfo, RenderObject* subtreeRoot, const TextAutosizingWindowInfo& windowInfo) { ASSERT(isAutosizingContainer(container)); @@ -242,7 +411,7 @@ void TextAutosizer::processContainer(float multiplier, RenderBlock* container, T writeDebugInfo(container, "container"); #endif - float localMultiplier = containerShouldBeAutosized(container) ? multiplier: 1; + float localMultiplier = (multiplier > 1 && containerShouldBeAutosized(container)) ? multiplier: 1; RenderObject* descendant = nextInPreOrderSkippingDescendantsOfContainers(subtreeRoot, subtreeRoot); while (descendant) { @@ -287,12 +456,12 @@ void TextAutosizer::setMultiplierForList(RenderObject* renderer, float multiplie #ifndef NDEBUG Node* parentNode = renderer->generatingNode(); ASSERT(parentNode); - ASSERT(parentNode->hasTagName(olTag) || parentNode->hasTagName(ulTag)); + ASSERT(isHTMLOListElement(parentNode) || isHTMLUListElement(parentNode)); #endif setMultiplier(renderer, multiplier); // Make sure all list items are autosized consistently. - for (RenderObject* child = renderer->firstChild(); child; child = child->nextSibling()) { + for (RenderObject* child = renderer->slowFirstChild(); child; child = child->nextSibling()) { if (child->isListItem() && child->style()->textAutosizingMultiplier() == 1) setMultiplier(child, multiplier); } @@ -337,7 +506,7 @@ bool TextAutosizer::isAutosizingContainer(const RenderObject* renderer) // - Must not be normal list items, as items in the same list should look // consistent, unless they are floating or position:absolute/fixed. Node* node = renderer->generatingNode(); - if ((node && !node->hasChildNodes()) + if ((node && !node->hasChildren()) || !renderer->isRenderBlock() || (renderer->isInline() && !renderer->style()->isDisplayReplacedType())) return false; @@ -367,14 +536,14 @@ bool TextAutosizer::isNarrowDescendant(const RenderBlock* renderer, TextAutosizi // the enclosing cluster. This 150px limit is adjusted whenever a descendant container is // less than 50px narrower than the current limit. const float differenceFromMaxWidthDifference = 50; - float contentWidth = renderer->contentLogicalWidth(); - float clusterTextWidth = parentClusterInfo.blockContainingAllText->contentLogicalWidth(); - float widthDifference = clusterTextWidth - contentWidth; + LayoutUnit contentWidth = renderer->contentLogicalWidth(); + LayoutUnit clusterTextWidth = parentClusterInfo.blockContainingAllText->contentLogicalWidth(); + LayoutUnit widthDifference = clusterTextWidth - contentWidth; if (widthDifference - parentClusterInfo.maxAllowedDifferenceFromTextWidth > differenceFromMaxWidthDifference) return true; - parentClusterInfo.maxAllowedDifferenceFromTextWidth = std::max(widthDifference, parentClusterInfo.maxAllowedDifferenceFromTextWidth); + parentClusterInfo.maxAllowedDifferenceFromTextWidth = std::max(widthDifference.toFloat(), parentClusterInfo.maxAllowedDifferenceFromTextWidth); return false; } @@ -384,8 +553,8 @@ bool TextAutosizer::isWiderDescendant(const RenderBlock* renderer, const TextAut // Autosizing containers that are wider than the |blockContainingAllText| of their enclosing // cluster are treated the same way as autosizing clusters to be autosized separately. - float contentWidth = renderer->contentLogicalWidth(); - float clusterTextWidth = parentClusterInfo.blockContainingAllText->contentLogicalWidth(); + LayoutUnit contentWidth = renderer->contentLogicalWidth(); + LayoutUnit clusterTextWidth = parentClusterInfo.blockContainingAllText->contentLogicalWidth(); return contentWidth > clusterTextWidth; } @@ -412,6 +581,7 @@ bool TextAutosizer::isIndependentDescendant(const RenderBlock* renderer) // from the box's parent (we want to avoid having significantly different // width blocks within a cluster, since the narrower blocks would end up // larger than would otherwise be necessary). + RenderBlock* containingBlock = renderer->containingBlock(); return renderer->isRenderView() || renderer->isFloating() || renderer->isOutOfFlowPositioned() @@ -419,7 +589,7 @@ bool TextAutosizer::isIndependentDescendant(const RenderBlock* renderer) || renderer->isTableCaption() || renderer->isFlexibleBoxIncludingDeprecated() || renderer->hasColumns() - || renderer->containingBlock()->isHorizontalWritingMode() != renderer->isHorizontalWritingMode() + || (containingBlock && containingBlock->isHorizontalWritingMode() != renderer->isHorizontalWritingMode()) || renderer->style()->isDisplayReplacedType() || renderer->isTextArea() || renderer->style()->userModify() != READ_ONLY; @@ -520,7 +690,7 @@ bool TextAutosizer::contentHeightIsConstrained(const RenderBlock* container) if (style->height().isSpecified() || style->maxHeight().isSpecified() || container->isOutOfFlowPositioned()) { // Some sites (e.g. wikipedia) set their html and/or body elements to height:100%, // without intending to constrain the height of the content within them. - return !container->isRoot() && !container->isBody(); + return !container->isDocumentElement() && !container->isBody(); } if (container->isFloating()) return false; @@ -528,12 +698,6 @@ bool TextAutosizer::contentHeightIsConstrained(const RenderBlock* container) return false; } -bool TextAutosizer::clusterShouldBeAutosized(TextAutosizingClusterInfo& clusterInfo, float blockWidth) -{ - Vector<TextAutosizingClusterInfo> clusterInfos(1, clusterInfo); - return compositeClusterShouldBeAutosized(clusterInfos, blockWidth); -} - bool TextAutosizer::compositeClusterShouldBeAutosized(Vector<TextAutosizingClusterInfo>& clusterInfos, float blockWidth) { // Don't autosize clusters that contain less than 4 lines of text (in @@ -634,11 +798,11 @@ const RenderBlock* TextAutosizer::findDeepestBlockContainingAllText(const Render const RenderObject* TextAutosizer::findFirstTextLeafNotInCluster(const RenderObject* parent, size_t& depth, TraversalDirection direction) { - if (parent->isEmpty()) - return parent->isText() ? parent : 0; + if (parent->isText()) + return parent; ++depth; - const RenderObject* child = (direction == FirstToLast) ? parent->firstChild() : parent->lastChild(); + const RenderObject* child = (direction == FirstToLast) ? parent->slowFirstChild() : parent->slowLastChild(); while (child) { if (!isAutosizingContainer(child) || !isIndependentDescendant(toRenderBlock(child))) { const RenderObject* leaf = findFirstTextLeafNotInCluster(child, depth, direction); @@ -681,8 +845,8 @@ void TextAutosizer::getNarrowDescendantsGroupedByWidth(const TextAutosizingClust groups.last().append(clusterInfos[i]); if (i + 1 < clusterInfos.size()) { - float currentWidth = clusterInfos[i].root->contentLogicalWidth(); - float nextWidth = clusterInfos[i + 1].root->contentLogicalWidth(); + LayoutUnit currentWidth = clusterInfos[i].root->contentLogicalWidth(); + LayoutUnit nextWidth = clusterInfos[i + 1].root->contentLogicalWidth(); if (currentWidth - nextWidth > maxWidthDifferenceWithinGroup) groups.grow(groups.size() + 1); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/TextAutosizer.h b/chromium/third_party/WebKit/Source/core/rendering/TextAutosizer.h index dda763efa7b..aac87074bb4 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/TextAutosizer.h +++ b/chromium/third_party/WebKit/Source/core/rendering/TextAutosizer.h @@ -26,9 +26,11 @@ #ifndef TextAutosizer_h #define TextAutosizer_h -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "platform/text/WritingMode.h" +#include "wtf/HashMap.h" #include "wtf/Noncopyable.h" +#include "wtf/OwnPtr.h" #include "wtf/PassOwnPtr.h" namespace WebCore { @@ -36,9 +38,28 @@ namespace WebCore { class Document; class RenderBlock; class RenderObject; -class RenderText; struct TextAutosizingWindowInfo; -struct TextAutosizingClusterInfo; + +// Represents cluster related data. Instances should not persist between calls to processSubtree. +struct TextAutosizingClusterInfo { + explicit TextAutosizingClusterInfo(RenderBlock* root) + : root(root) + , blockContainingAllText(0) + , maxAllowedDifferenceFromTextWidth(150) + { + } + + RenderBlock* root; + const RenderBlock* blockContainingAllText; + + // Upper limit on the difference between the width of the cluster's block containing all + // text and that of a narrow child before the child becomes a separate cluster. + float maxAllowedDifferenceFromTextWidth; + + // Descendants of the cluster that are narrower than the block containing all text and must be + // processed together. + Vector<TextAutosizingClusterInfo> narrowDescendants; +}; class TextAutosizer FINAL { WTF_MAKE_NONCOPYABLE(TextAutosizer); @@ -61,6 +82,7 @@ private: explicit TextAutosizer(Document*); + bool isApplicable() const; float clusterMultiplier(WritingMode, const TextAutosizingWindowInfo&, float textWidth) const; void processClusterInternal(TextAutosizingClusterInfo&, RenderBlock* container, RenderObject* subtreeRoot, const TextAutosizingWindowInfo&, float multiplier); @@ -71,6 +93,8 @@ private: void setMultiplier(RenderObject*, float); void setMultiplierForList(RenderObject* renderer, float multiplier); + unsigned getCachedHash(const RenderObject* renderer, bool putInCacheIfAbsent); + static bool isAutosizingContainer(const RenderObject*); static bool isNarrowDescendant(const RenderBlock*, TextAutosizingClusterInfo& parentClusterInfo); static bool isWiderDescendant(const RenderBlock*, const TextAutosizingClusterInfo& parentClusterInfo); @@ -81,9 +105,10 @@ private: static bool containerContainsOneOfTags(const RenderBlock* cluster, const Vector<QualifiedName>& tags); static bool containerIsRowOfLinks(const RenderObject* container); static bool contentHeightIsConstrained(const RenderBlock* container); - static bool clusterShouldBeAutosized(TextAutosizingClusterInfo&, float blockWidth); static bool compositeClusterShouldBeAutosized(Vector<TextAutosizingClusterInfo>&, float blockWidth); static void measureDescendantTextWidth(const RenderBlock* container, TextAutosizingClusterInfo&, float minTextWidth, float& textWidth); + unsigned computeCompositeClusterHash(Vector<TextAutosizingClusterInfo>&); + float computeMultiplier(Vector<TextAutosizingClusterInfo>&, const TextAutosizingWindowInfo&, float textWidth); // Use to traverse the tree of descendants, excluding descendants of containers (but returning the containers themselves). static RenderObject* nextInPreOrderSkippingDescendantsOfContainers(const RenderObject*, const RenderObject* stayWithin); @@ -99,7 +124,22 @@ private: // |blockContainingAllText|. static void getNarrowDescendantsGroupedByWidth(const TextAutosizingClusterInfo& parentClusterInfo, Vector<Vector<TextAutosizingClusterInfo> >&); + void addNonAutosizedCluster(unsigned key, TextAutosizingClusterInfo& value); + void secondPassProcessStaleNonAutosizedClusters(); + void processStaleContainer(float multiplier, RenderBlock* cluster, TextAutosizingClusterInfo&); + Document* m_document; + + HashMap<const RenderObject*, unsigned> m_hashCache; + + // Mapping from all autosized (i.e. multiplier > 1) cluster hashes to their respective multipliers. + HashMap<unsigned, float> m_hashToMultiplier; + Vector<unsigned> m_hashesToAutosizeSecondPass; + + // Mapping from a cluster hash to the corresponding cluster infos which have not been autosized yet. + HashMap<unsigned, OwnPtr<Vector<TextAutosizingClusterInfo> > > m_nonAutosizedClusters; + + bool m_previouslyAutosized; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/TrailingFloatsRootInlineBox.h b/chromium/third_party/WebKit/Source/core/rendering/TrailingFloatsRootInlineBox.h index 8036f5a0432..151f0b08b19 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/TrailingFloatsRootInlineBox.h +++ b/chromium/third_party/WebKit/Source/core/rendering/TrailingFloatsRootInlineBox.h @@ -32,14 +32,14 @@ namespace WebCore { class TrailingFloatsRootInlineBox FINAL : public RootInlineBox { public: - TrailingFloatsRootInlineBox(RenderBlockFlow* block) + TrailingFloatsRootInlineBox(RenderBlockFlow& block) : RootInlineBox(block) { setHasVirtualLogicalHeight(); } private: - virtual float virtualLogicalHeight() const { return 0; } + virtual float virtualLogicalHeight() const OVERRIDE { return 0; } }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/animation/WebAnimationProvider.cpp b/chromium/third_party/WebKit/Source/core/rendering/animation/WebAnimationProvider.cpp deleted file mode 100644 index 473e3ff8073..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/animation/WebAnimationProvider.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2013 Intel Corporation. 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 "core/rendering/animation/WebAnimationProvider.h" - -#include "core/platform/animation/AnimationTranslationUtil.h" -#include "core/platform/animation/CSSAnimationData.h" -#include "core/rendering/style/KeyframeList.h" -#include "core/rendering/style/RenderStyle.h" -#include "public/platform/WebAnimation.h" -#include "wtf/text/StringBuilder.h" - -using blink::WebAnimation; - -namespace WebCore { - -namespace { - -String animationNameForTransition(AnimatedPropertyID property) -{ - // | is not a valid identifier character in CSS, so this can never conflict with a keyframe identifier. - StringBuilder id; - id.appendLiteral("-|transition"); - id.appendNumber(static_cast<int>(property)); - id.append('-'); - return id.toString(); -} - -AnimatedPropertyID cssToGraphicsLayerProperty(CSSPropertyID cssProperty) -{ - switch (cssProperty) { - case CSSPropertyWebkitTransform: - return AnimatedPropertyWebkitTransform; - case CSSPropertyOpacity: - return AnimatedPropertyOpacity; - case CSSPropertyBackgroundColor: - ASSERT_NOT_REACHED(); - return AnimatedPropertyInvalid; // Chromium compositor cannot accelerate background color yet. - case CSSPropertyWebkitFilter: - return AnimatedPropertyWebkitFilter; - default: - // It's fine if we see other css properties here; they are just not accelerated. - break; - } - return AnimatedPropertyInvalid; -} - -} // namespace - -WebAnimations::WebAnimations() -{ -} - -WebAnimations::~WebAnimations() -{ -} - -// Copy constructor is needed to use this struct as a return value. It actually moves the ownership, not copy. -WebAnimations::WebAnimations(const WebAnimations& other) -{ - ASSERT(isEmpty()); - m_transformAnimation.swap(const_cast<OwnPtr<WebAnimation>& >(other.m_transformAnimation)); - m_opacityAnimation.swap(const_cast<OwnPtr<WebAnimation>& >(other.m_opacityAnimation)); - m_filterAnimation.swap(const_cast<OwnPtr<WebAnimation>& >(other.m_filterAnimation)); - ASSERT(other.isEmpty()); -} - -bool WebAnimations::isEmpty() const -{ - return !m_transformAnimation && !m_opacityAnimation && !m_filterAnimation; -} - -WebAnimationProvider::WebAnimationProvider() -{ -} - -WebAnimationProvider::~WebAnimationProvider() -{ -} - -int WebAnimationProvider::getWebAnimationId(const String& animationName) const -{ - if (!m_animationIdMap.contains(animationName)) - return 0; - return m_animationIdMap.get(animationName); -} - -int WebAnimationProvider::getWebAnimationId(CSSPropertyID property) const -{ - AnimatedPropertyID animatedProperty = cssToGraphicsLayerProperty(property); - ASSERT(animatedProperty != AnimatedPropertyInvalid); - return getWebAnimationId(animationNameForTransition(animatedProperty)); -} - -WebAnimations WebAnimationProvider::startAnimation(double timeOffset, const CSSAnimationData* anim, const KeyframeList& keyframes, bool hasTransform, const IntSize& boxSize) -{ - ASSERT(hasTransform || boxSize.isEmpty()); - bool hasOpacity = keyframes.containsProperty(CSSPropertyOpacity); - bool hasFilter = keyframes.containsProperty(CSSPropertyWebkitFilter); - - if (!hasOpacity && !hasTransform && !hasFilter) - return WebAnimations(); - - KeyframeValueList transformVector(AnimatedPropertyWebkitTransform); - KeyframeValueList opacityVector(AnimatedPropertyOpacity); - KeyframeValueList filterVector(AnimatedPropertyWebkitFilter); - - size_t numKeyframes = keyframes.size(); - for (size_t i = 0; i < numKeyframes; ++i) { - const KeyframeValue& currentKeyframe = keyframes[i]; - const RenderStyle* keyframeStyle = currentKeyframe.style(); - double key = currentKeyframe.key(); - - if (!keyframeStyle) - continue; - - // Get timing function. - RefPtr<TimingFunction> tf = KeyframeValue::timingFunction(*keyframeStyle); - - bool isFirstOrLastKeyframe = !key || key == 1; - if ((hasTransform && isFirstOrLastKeyframe) || currentKeyframe.containsProperty(CSSPropertyWebkitTransform)) - transformVector.insert(adoptPtr(new TransformAnimationValue(key, &(keyframeStyle->transform()), tf))); - - if ((hasOpacity && isFirstOrLastKeyframe) || currentKeyframe.containsProperty(CSSPropertyOpacity)) - opacityVector.insert(adoptPtr(new FloatAnimationValue(key, keyframeStyle->opacity(), tf))); - - if ((hasFilter && isFirstOrLastKeyframe) || currentKeyframe.containsProperty(CSSPropertyWebkitFilter)) - filterVector.insert(adoptPtr(new FilterAnimationValue(key, &(keyframeStyle->filter()), tf))); - } - WebAnimations resultAnimations; - if (hasTransform) - resultAnimations.m_transformAnimation = createWebAnimationAndStoreId(transformVector, boxSize, anim, keyframes.animationName(), timeOffset); - if (hasOpacity) - resultAnimations.m_opacityAnimation = createWebAnimationAndStoreId(opacityVector, IntSize(), anim, keyframes.animationName(), timeOffset); - if (hasFilter) - resultAnimations.m_filterAnimation = createWebAnimationAndStoreId(filterVector, IntSize(), anim, keyframes.animationName(), timeOffset); - - return resultAnimations; -} - -WebAnimations WebAnimationProvider::startTransition(double timeOffset, CSSPropertyID property, const RenderStyle* fromStyle, const RenderStyle* toStyle, bool hasTransform, bool hasFilter, const IntSize& boxSize, float fromOpacity, float toOpacity) -{ - ASSERT(property != CSSPropertyInvalid); - ASSERT(property == CSSPropertyOpacity || (!fromOpacity && !toOpacity)); - - WebAnimations resultAnimations; - if (property == CSSPropertyOpacity) { - const CSSAnimationData* opacityAnim = toStyle->transitionForProperty(CSSPropertyOpacity); - if (opacityAnim && !opacityAnim->isEmptyOrZeroDuration()) { - KeyframeValueList opacityVector(AnimatedPropertyOpacity); - opacityVector.insert(adoptPtr(new FloatAnimationValue(0, fromOpacity))); - opacityVector.insert(adoptPtr(new FloatAnimationValue(1, toOpacity))); - resultAnimations.m_opacityAnimation = createWebAnimationAndStoreId(opacityVector, IntSize(), opacityAnim, animationNameForTransition(AnimatedPropertyOpacity), timeOffset); - } - } - if (property == CSSPropertyWebkitTransform && hasTransform) { - const CSSAnimationData* transformAnim = toStyle->transitionForProperty(CSSPropertyWebkitTransform); - if (transformAnim && !transformAnim->isEmptyOrZeroDuration()) { - KeyframeValueList transformVector(AnimatedPropertyWebkitTransform); - transformVector.insert(adoptPtr(new TransformAnimationValue(0, &fromStyle->transform()))); - transformVector.insert(adoptPtr(new TransformAnimationValue(1, &toStyle->transform()))); - resultAnimations.m_transformAnimation = createWebAnimationAndStoreId(transformVector, boxSize, transformAnim, animationNameForTransition(AnimatedPropertyWebkitTransform), timeOffset); - } - } - if (property == CSSPropertyWebkitFilter && hasFilter) { - const CSSAnimationData* filterAnim = toStyle->transitionForProperty(CSSPropertyWebkitFilter); - if (filterAnim && !filterAnim->isEmptyOrZeroDuration()) { - KeyframeValueList filterVector(AnimatedPropertyWebkitFilter); - filterVector.insert(adoptPtr(new FilterAnimationValue(0, &fromStyle->filter()))); - filterVector.insert(adoptPtr(new FilterAnimationValue(1, &toStyle->filter()))); - resultAnimations.m_filterAnimation = createWebAnimationAndStoreId(filterVector, IntSize(), filterAnim, animationNameForTransition(AnimatedPropertyWebkitFilter), timeOffset); - } - } - - return resultAnimations; -} - -PassOwnPtr<WebAnimation> WebAnimationProvider::createWebAnimationAndStoreId(const KeyframeValueList& values, const IntSize& boxSize, const CSSAnimationData* animation, const String& animationName, double timeOffset) -{ - int animationId = getWebAnimationId(animationName); - OwnPtr<WebAnimation> webAnimation(createWebAnimation(values, animation, animationId, timeOffset, boxSize)); - if (!webAnimation) - return PassOwnPtr<WebAnimation>(); - - if (!animationId) - m_animationIdMap.set(animationName, webAnimation->id()); - return webAnimation.release(); -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/animation/WebAnimationProvider.h b/chromium/third_party/WebKit/Source/core/rendering/animation/WebAnimationProvider.h deleted file mode 100644 index 724de2e1696..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/animation/WebAnimationProvider.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2013 Intel Corporation. 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 WebAnimationProvider_h -#define WebAnimationProvider_h - -#include "CSSPropertyNames.h" -#include "core/platform/animation/KeyframeValueList.h" -#include "wtf/HashMap.h" -#include "wtf/OwnPtr.h" -#include "wtf/PassOwnPtr.h" -#include "wtf/text/WTFString.h" - -namespace blink { -class WebAnimation; -} - -namespace WebCore { -class CSSAnimationData; -class IntSize; -class KeyframeList; -class RenderStyle; - -struct WebAnimations { - WebAnimations(); - ~WebAnimations(); - WebAnimations(const WebAnimations&); - bool isEmpty() const; - OwnPtr<blink::WebAnimation> m_transformAnimation; - OwnPtr<blink::WebAnimation> m_opacityAnimation; - OwnPtr<blink::WebAnimation> m_filterAnimation; -}; - -class WebAnimationProvider { - WTF_MAKE_NONCOPYABLE(WebAnimationProvider); WTF_MAKE_FAST_ALLOCATED; -public: - WebAnimationProvider(); - ~WebAnimationProvider(); - - int getWebAnimationId(const String& animationName) const; - int getWebAnimationId(CSSPropertyID) const; - WebAnimations startAnimation(double timeOffset, const CSSAnimationData*, const KeyframeList&, bool hasTransform, const IntSize& boxSize); - WebAnimations startTransition(double timeOffset, CSSPropertyID, const RenderStyle* fromStyle, const RenderStyle* toStyle, bool hasTransform, bool hasFilter, const IntSize& boxSize, float fromOpacity, float toOpacity); - -private: - PassOwnPtr<blink::WebAnimation> createWebAnimationAndStoreId(const KeyframeValueList&, const IntSize& boxSize, const CSSAnimationData*, const String& animationName, double timeOffset); - - typedef HashMap<String, int> AnimationIdMap; - AnimationIdMap m_animationIdMap; -}; - -} // namespace WebCore - -#endif // WebAnimationProvider_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMapping.cpp b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMapping.cpp new file mode 100644 index 00000000000..0b01a059bc5 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMapping.cpp @@ -0,0 +1,2246 @@ +/* + * Copyright (C) 2009, 2010, 2011 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 "core/rendering/compositing/CompositedLayerMapping.h" + +#include "core/HTMLNames.h" +#include "core/fetch/ImageResource.h" +#include "core/html/HTMLCanvasElement.h" +#include "core/html/HTMLIFrameElement.h" +#include "core/html/HTMLMediaElement.h" +#include "core/html/canvas/CanvasRenderingContext.h" +#include "core/inspector/InspectorInstrumentation.h" +#include "core/inspector/InspectorNodeIds.h" +#include "core/inspector/InspectorTraceEvents.h" +#include "core/page/Chrome.h" +#include "core/frame/FrameView.h" +#include "core/page/scrolling/ScrollingCoordinator.h" +#include "core/plugins/PluginView.h" +#include "core/rendering/FilterEffectRenderer.h" +#include "core/rendering/RenderImage.h" +#include "core/rendering/RenderLayerStackingNodeIterator.h" +#include "core/rendering/RenderVideo.h" +#include "core/rendering/RenderView.h" +#include "core/rendering/compositing/RenderLayerCompositor.h" +#include "core/rendering/style/KeyframeList.h" +#include "platform/LengthFunctions.h" +#include "platform/RuntimeEnabledFeatures.h" +#include "platform/fonts/FontCache.h" +#include "platform/graphics/GraphicsContext.h" +#include "wtf/CurrentTime.h" +#include "wtf/text/StringBuilder.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +static IntRect clipBox(RenderBox* renderer); + +static IntRect contentsRect(const RenderObject* renderer) +{ + if (!renderer->isBox()) + return IntRect(); + + return renderer->isVideo() ? + toRenderVideo(renderer)->videoBox() : + pixelSnappedIntRect(toRenderBox(renderer)->contentBoxRect()); +} + +static IntRect backgroundRect(const RenderObject* renderer) +{ + if (!renderer->isBox()) + return IntRect(); + + LayoutRect rect; + const RenderBox* box = toRenderBox(renderer); + EFillBox clip = box->style()->backgroundClip(); + switch (clip) { + case BorderFillBox: + rect = box->borderBoxRect(); + break; + case PaddingFillBox: + rect = box->paddingBoxRect(); + break; + case ContentFillBox: + rect = box->contentBoxRect(); + break; + case TextFillBox: + break; + } + + return pixelSnappedIntRect(rect); +} + +static inline bool isAcceleratedCanvas(const RenderObject* renderer) +{ + if (renderer->isCanvas()) { + HTMLCanvasElement* canvas = toHTMLCanvasElement(renderer->node()); + if (CanvasRenderingContext* context = canvas->renderingContext()) + return context->isAccelerated(); + } + return false; +} + +static bool hasBoxDecorations(const RenderStyle* style) +{ + return style->hasBorder() || style->hasBorderRadius() || style->hasOutline() || style->hasAppearance() || style->boxShadow() || style->hasFilter(); +} + +static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle* style) +{ + return hasBoxDecorations(style) || style->hasBackgroundImage(); +} + +static bool contentLayerSupportsDirectBackgroundComposition(const RenderObject* renderer) +{ + // No support for decorations - border, border-radius or outline. + // Only simple background - solid color or transparent. + if (hasBoxDecorationsOrBackgroundImage(renderer->style())) + return false; + + // If there is no background, there is nothing to support. + if (!renderer->style()->hasBackground()) + return true; + + // Simple background that is contained within the contents rect. + return contentsRect(renderer).contains(backgroundRect(renderer)); +} + +static blink::WebLayer* platformLayerForPlugin(RenderObject* renderer) +{ + if (!renderer->isEmbeddedObject()) + return 0; + Widget* widget = toRenderEmbeddedObject(renderer)->widget(); + if (!widget || !widget->isPluginView()) + return 0; + return toPluginView(widget)->platformLayer(); + +} + +static inline bool isAcceleratedContents(RenderObject* renderer) +{ + return isAcceleratedCanvas(renderer) + || (renderer->isEmbeddedObject() && toRenderEmbeddedObject(renderer)->requiresAcceleratedCompositing()) + || renderer->isVideo(); +} + +// Get the scrolling coordinator in a way that works inside CompositedLayerMapping's destructor. +static ScrollingCoordinator* scrollingCoordinatorFromLayer(RenderLayer& layer) +{ + Page* page = layer.renderer()->frame()->page(); + if (!page) + return 0; + + return page->scrollingCoordinator(); +} + +CompositedLayerMapping::CompositedLayerMapping(RenderLayer& layer) + : m_owningLayer(layer) + , m_pendingUpdateScope(GraphicsLayerUpdateNone) + , m_isMainFrameRenderViewLayer(false) + , m_requiresOwnBackingStoreForIntrinsicReasons(true) + , m_requiresOwnBackingStoreForAncestorReasons(true) + , m_canCompositeFilters(false) + , m_backgroundLayerPaintsFixedRootBackground(false) + , m_scrollingContentsAreEmpty(false) +{ + if (layer.isRootLayer() && renderer()->frame()->isMainFrame()) + m_isMainFrameRenderViewLayer = true; + + createPrimaryGraphicsLayer(); +} + +CompositedLayerMapping::~CompositedLayerMapping() +{ + // Hits in compositing/squashing/squash-onto-nephew.html. + DisableCompositingQueryAsserts disabler; + + // Do not leave the destroyed pointer dangling on any RenderLayers that painted to this mapping's squashing layer. + for (size_t i = 0; i < m_squashedLayers.size(); ++i) { + RenderLayer* oldSquashedLayer = m_squashedLayers[i].renderLayer; + if (oldSquashedLayer->groupedMapping() == this) { + oldSquashedLayer->setGroupedMapping(0, true); + oldSquashedLayer->setLostGroupedMapping(true); + } + } + + updateClippingLayers(false, false); + updateOverflowControlsLayers(false, false, false); + updateChildTransformLayer(false); + updateForegroundLayer(false); + updateBackgroundLayer(false); + updateMaskLayer(false); + updateClippingMaskLayers(false); + updateScrollingLayers(false); + updateSquashingLayers(false); + destroyGraphicsLayers(); +} + +PassOwnPtr<GraphicsLayer> CompositedLayerMapping::createGraphicsLayer(CompositingReasons reasons) +{ + GraphicsLayerFactory* graphicsLayerFactory = 0; + if (Page* page = renderer()->frame()->page()) + graphicsLayerFactory = page->chrome().client().graphicsLayerFactory(); + + OwnPtr<GraphicsLayer> graphicsLayer = GraphicsLayer::create(graphicsLayerFactory, this); + + graphicsLayer->setCompositingReasons(reasons); + if (Node* owningNode = m_owningLayer.renderer()->generatingNode()) + graphicsLayer->setOwnerNodeId(InspectorNodeIds::idForNode(owningNode)); + + return graphicsLayer.release(); +} + +void CompositedLayerMapping::createPrimaryGraphicsLayer() +{ + m_graphicsLayer = createGraphicsLayer(m_owningLayer.compositingReasons()); + +#if !OS(ANDROID) + if (m_isMainFrameRenderViewLayer) + m_graphicsLayer->contentLayer()->setDrawCheckerboardForMissingTiles(true); +#endif + + updateOpacity(renderer()->style()); + updateTransform(renderer()->style()); + updateFilters(renderer()->style()); + + if (RuntimeEnabledFeatures::cssCompositingEnabled()) { + updateLayerBlendMode(renderer()->style()); + updateIsRootForIsolatedGroup(); + } +} + +void CompositedLayerMapping::destroyGraphicsLayers() +{ + if (m_graphicsLayer) + m_graphicsLayer->removeFromParent(); + + m_ancestorClippingLayer = nullptr; + m_graphicsLayer = nullptr; + m_foregroundLayer = nullptr; + m_backgroundLayer = nullptr; + m_childContainmentLayer = nullptr; + m_childTransformLayer = nullptr; + m_maskLayer = nullptr; + m_childClippingMaskLayer = nullptr; + + m_scrollingLayer = nullptr; + m_scrollingContentsLayer = nullptr; + m_scrollingBlockSelectionLayer = nullptr; +} + +void CompositedLayerMapping::updateOpacity(const RenderStyle* style) +{ + m_graphicsLayer->setOpacity(compositingOpacity(style->opacity())); +} + +void CompositedLayerMapping::updateTransform(const RenderStyle* style) +{ + // FIXME: This could use m_owningLayer.transform(), but that currently has transform-origin + // baked into it, and we don't want that. + TransformationMatrix t; + if (m_owningLayer.hasTransform()) { + style->applyTransform(t, toRenderBox(renderer())->pixelSnappedBorderBoxRect().size(), RenderStyle::ExcludeTransformOrigin); + makeMatrixRenderable(t, compositor()->hasAcceleratedCompositing()); + } + + m_graphicsLayer->setTransform(t); +} + +void CompositedLayerMapping::updateFilters(const RenderStyle* style) +{ + unsigned didCompositeFilters = m_canCompositeFilters; + m_canCompositeFilters = m_graphicsLayer->setFilters(owningLayer().computeFilterOperations(style)); + if (didCompositeFilters != m_canCompositeFilters) { + // + // If filters used to be painted in software and are now painted in the compositor, we need to: + // (1) Remove the FilterEffectRenderer, which was used for painting filters in software. + // (2) Repaint the layer contents to remove the software-applied filter because the compositor will apply it. + // + // Similarly, if filters used to be painted in the compositor and are now painted in software, we need to: + // (1) Create a FilterEffectRenderer. + // (2) Repaint the layer contents to apply a software filter because the compositor won't apply it. + // + m_owningLayer.updateOrRemoveFilterEffectRenderer(); + setContentsNeedDisplay(); + } +} + +void CompositedLayerMapping::updateLayerBlendMode(const RenderStyle* style) +{ + setBlendMode(style->blendMode()); +} + +void CompositedLayerMapping::updateIsRootForIsolatedGroup() +{ + bool isolate = m_owningLayer.shouldIsolateCompositedDescendants(); + + // non stacking context layers should never isolate + ASSERT(m_owningLayer.stackingNode()->isStackingContext() || !isolate); + + m_graphicsLayer->setIsRootForIsolatedGroup(isolate); +} + +void CompositedLayerMapping::updateContentsOpaque() +{ + // For non-root layers, background is always painted by the primary graphics layer. + ASSERT(m_isMainFrameRenderViewLayer || !m_backgroundLayer); + if (m_backgroundLayer) { + m_graphicsLayer->setContentsOpaque(false); + m_backgroundLayer->setContentsOpaque(m_owningLayer.backgroundIsKnownToBeOpaqueInRect(compositedBounds())); + } else { + m_graphicsLayer->setContentsOpaque(m_owningLayer.backgroundIsKnownToBeOpaqueInRect(compositedBounds())); + } +} + +void CompositedLayerMapping::updateCompositedBounds(GraphicsLayerUpdater::UpdateType updateType) +{ + if (!shouldUpdateGraphicsLayer(updateType)) + return; + + // FIXME: if this is really needed for performance, it would be better to store it on RenderLayer. + m_compositedBounds = m_owningLayer.boundingBoxForCompositing(); +} + +void CompositedLayerMapping::updateAfterWidgetResize() +{ + if (renderer()->isRenderPart()) { + if (RenderLayerCompositor* innerCompositor = RenderLayerCompositor::frameContentsCompositor(toRenderPart(renderer()))) { + innerCompositor->frameViewDidChangeSize(); + // We can floor this point because our frameviews are always aligned to pixel boundaries. + ASSERT(contentsBox().location() == flooredIntPoint(contentsBox().location())); + innerCompositor->frameViewDidChangeLocation(flooredIntPoint(contentsBox().location())); + } + } +} + +void CompositedLayerMapping::updateCompositingReasons() +{ + // All other layers owned by this mapping will have the same compositing reason + // for their lifetime, so they are initialized only when created. + m_graphicsLayer->setCompositingReasons(m_owningLayer.compositingReasons()); +} + +bool CompositedLayerMapping::updateGraphicsLayerConfiguration(GraphicsLayerUpdater::UpdateType updateType) +{ + if (!shouldUpdateGraphicsLayer(updateType)) + return false; + + RenderLayerCompositor* compositor = this->compositor(); + RenderObject* renderer = this->renderer(); + + m_owningLayer.updateDescendantDependentFlags(); + m_owningLayer.stackingNode()->updateZOrderLists(); + + bool layerConfigChanged = false; + setBackgroundLayerPaintsFixedRootBackground(compositor->needsFixedRootBackgroundLayer(&m_owningLayer)); + + // The background layer is currently only used for fixed root backgrounds. + if (updateBackgroundLayer(m_backgroundLayerPaintsFixedRootBackground)) + layerConfigChanged = true; + + if (updateForegroundLayer(compositor->needsContentsCompositingLayer(&m_owningLayer))) + layerConfigChanged = true; + + bool needsDescendantsClippingLayer = compositor->clipsCompositingDescendants(&m_owningLayer); + + // Our scrolling layer will clip. + if (m_owningLayer.needsCompositedScrolling()) + needsDescendantsClippingLayer = false; + + RenderLayer* scrollParent = compositor->acceleratedCompositingForOverflowScrollEnabled() ? m_owningLayer.scrollParent() : 0; + bool needsAncestorClip = compositor->clippedByNonAncestorInStackingTree(&m_owningLayer); + if (scrollParent) { + // If our containing block is our ancestor scrolling layer, then we'll already be clipped + // to it via our scroll parent and we don't need an ancestor clipping layer. + if (m_owningLayer.renderer()->containingBlock()->enclosingLayer() == m_owningLayer.ancestorScrollingLayer()) + needsAncestorClip = false; + } + + if (updateClippingLayers(needsAncestorClip, needsDescendantsClippingLayer)) + layerConfigChanged = true; + + if (updateOverflowControlsLayers(requiresHorizontalScrollbarLayer(), requiresVerticalScrollbarLayer(), requiresScrollCornerLayer())) + layerConfigChanged = true; + + bool scrollingConfigChanged = false; + if (updateScrollingLayers(m_owningLayer.needsCompositedScrolling())) { + layerConfigChanged = true; + scrollingConfigChanged = true; + } + + bool hasPerspective = false; + if (RenderStyle* style = renderer->style()) + hasPerspective = style->hasPerspective(); + bool needsChildTransformLayer = hasPerspective && (layerForChildrenTransform() == m_childTransformLayer.get()) && renderer->isBox(); + if (updateChildTransformLayer(needsChildTransformLayer)) + layerConfigChanged = true; + + updateScrollParent(scrollParent); + updateClipParent(m_owningLayer.clipParent()); + + if (updateSquashingLayers(!m_squashedLayers.isEmpty())) + layerConfigChanged = true; + + if (layerConfigChanged) + updateInternalHierarchy(); + + if (scrollingConfigChanged) { + if (renderer->view()) + compositor->scrollingLayerDidChange(&m_owningLayer); + } + + // A mask layer is not part of the hierarchy proper, it's an auxiliary layer + // that's plugged into another GraphicsLayer that is part of the hierarchy. + // It has no parent or child GraphicsLayer. For that reason, we process it + // here, after the hierarchy has been updated. + bool maskLayerChanged = false; + if (updateMaskLayer(renderer->hasMask())) { + maskLayerChanged = true; + m_graphicsLayer->setMaskLayer(m_maskLayer.get()); + } + + bool hasChildClippingLayer = compositor->clipsCompositingDescendants(&m_owningLayer) && (hasClippingLayer() || hasScrollingLayer()); + // If we have a border radius or clip path on a scrolling layer, we need a clipping mask to properly + // clip the scrolled contents, even if there are no composited descendants. + bool hasClipPath = renderer->style()->clipPath(); + bool needsChildClippingMask = (hasClipPath || renderer->style()->hasBorderRadius()) && (hasChildClippingLayer || isAcceleratedContents(renderer) || hasScrollingLayer()); + if (updateClippingMaskLayers(needsChildClippingMask)) { + // Clip path clips the entire subtree, including scrollbars. It must be attached directly onto + // the main m_graphicsLayer. + if (hasClipPath) + m_graphicsLayer->setMaskLayer(m_childClippingMaskLayer.get()); + else if (hasClippingLayer()) + clippingLayer()->setMaskLayer(m_childClippingMaskLayer.get()); + else if (hasScrollingLayer()) + scrollingLayer()->setMaskLayer(m_childClippingMaskLayer.get()); + else if (isAcceleratedContents(renderer)) + m_graphicsLayer->setContentsClippingMaskLayer(m_childClippingMaskLayer.get()); + } + + if (m_owningLayer.reflectionInfo()) { + if (m_owningLayer.reflectionInfo()->reflectionLayer()->hasCompositedLayerMapping()) { + GraphicsLayer* reflectionLayer = m_owningLayer.reflectionInfo()->reflectionLayer()->compositedLayerMapping()->mainGraphicsLayer(); + m_graphicsLayer->setReplicatedByLayer(reflectionLayer); + } + } else { + m_graphicsLayer->setReplicatedByLayer(0); + } + + updateBackgroundColor(); + + if (isDirectlyCompositedImage()) + updateImageContents(); + + if (blink::WebLayer* layer = platformLayerForPlugin(renderer)) { + m_graphicsLayer->setContentsToPlatformLayer(layer); + } else if (renderer->node() && renderer->node()->isFrameOwnerElement() && toHTMLFrameOwnerElement(renderer->node())->contentFrame()) { + blink::WebLayer* layer = toHTMLFrameOwnerElement(renderer->node())->contentFrame()->remotePlatformLayer(); + if (layer) + m_graphicsLayer->setContentsToPlatformLayer(layer); + } else if (renderer->isVideo()) { + HTMLMediaElement* mediaElement = toHTMLMediaElement(renderer->node()); + m_graphicsLayer->setContentsToPlatformLayer(mediaElement->platformLayer()); + } else if (isAcceleratedCanvas(renderer)) { + HTMLCanvasElement* canvas = toHTMLCanvasElement(renderer->node()); + if (CanvasRenderingContext* context = canvas->renderingContext()) + m_graphicsLayer->setContentsToPlatformLayer(context->platformLayer()); + layerConfigChanged = true; + } + if (renderer->isRenderPart()) + layerConfigChanged = RenderLayerCompositor::parentFrameContentLayers(toRenderPart(renderer)); + + // Changes to either the internal hierarchy or the mask layer have an impact + // on painting phases, so we need to update when either are updated. + if (layerConfigChanged || maskLayerChanged) + updatePaintingPhases(); + + return layerConfigChanged; +} + +static IntRect clipBox(RenderBox* renderer) +{ + LayoutRect result = PaintInfo::infiniteRect(); + if (renderer->hasOverflowClip()) + result = renderer->overflowClipRect(LayoutPoint()); + + if (renderer->hasClip()) + result.intersect(renderer->clipRect(LayoutPoint())); + + return pixelSnappedIntRect(result); +} + +static LayoutPoint computeOffsetFromCompositedAncestor(const RenderLayer* layer, const RenderLayer* compositedAncestor) +{ + LayoutPoint offset; + layer->convertToLayerCoords(compositedAncestor, offset); + if (compositedAncestor) + offset.move(compositedAncestor->compositedLayerMapping()->owningLayer().subpixelAccumulation()); + return offset; +} + +void CompositedLayerMapping::computeBoundsOfOwningLayer(const RenderLayer* compositedAncestor, IntRect& localBounds, IntRect& compositingBoundsRelativeToCompositedAncestor, LayoutPoint& offsetFromCompositedAncestor, + IntPoint& snappedOffsetFromCompositedAncestor) +{ + LayoutRect localRawCompositingBounds = compositedBounds(); + offsetFromCompositedAncestor = computeOffsetFromCompositedAncestor(&m_owningLayer, compositedAncestor); + snappedOffsetFromCompositedAncestor = IntPoint(offsetFromCompositedAncestor.x().round(), offsetFromCompositedAncestor.y().round()); + + LayoutSize subpixelAccumulation = offsetFromCompositedAncestor - snappedOffsetFromCompositedAncestor; + m_owningLayer.setSubpixelAccumulation(subpixelAccumulation); + + // Move the bounds by the subpixel accumulation so that it pixel-snaps relative to absolute pixels instead of local coordinates. + localRawCompositingBounds.move(subpixelAccumulation); + localBounds = pixelSnappedIntRect(localRawCompositingBounds); + + compositingBoundsRelativeToCompositedAncestor = localBounds; + compositingBoundsRelativeToCompositedAncestor.moveBy(snappedOffsetFromCompositedAncestor); +} + +void CompositedLayerMapping::updateSquashingLayerGeometry(const LayoutPoint& offsetFromCompositedAncestor, const IntPoint& graphicsLayerParentLocation, const RenderLayer& referenceLayer, + Vector<GraphicsLayerPaintInfo>& layers, GraphicsLayer* squashingLayer, LayoutPoint* offsetFromTransformedAncestor, Vector<RenderLayer*>& layersNeedingPaintInvalidation) +{ + if (!squashingLayer) + return; + ASSERT(compositor()->layerSquashingEnabled()); + + LayoutPoint offsetFromReferenceLayerToParentGraphicsLayer(offsetFromCompositedAncestor); + offsetFromReferenceLayerToParentGraphicsLayer.moveBy(-graphicsLayerParentLocation); + + // FIXME: Cache these offsets. + LayoutPoint referenceOffsetFromTransformedAncestor = referenceLayer.computeOffsetFromTransformedAncestor(); + + LayoutRect totalSquashBounds; + for (size_t i = 0; i < layers.size(); ++i) { + LayoutRect squashedBounds = layers[i].renderLayer->boundingBoxForCompositing(); + + // Store the local bounds of the RenderLayer subtree before applying the offset. + layers[i].compositedBounds = squashedBounds; + + LayoutPoint offsetFromTransformedAncestorForSquashedLayer = layers[i].renderLayer->computeOffsetFromTransformedAncestor(); + LayoutSize offsetFromSquashingLayer = offsetFromTransformedAncestorForSquashedLayer - referenceOffsetFromTransformedAncestor; + + squashedBounds.move(offsetFromSquashingLayer); + totalSquashBounds.unite(squashedBounds); + } + + // The totalSquashBounds is positioned with respect to referenceLayer of this CompositedLayerMapping. + // But the squashingLayer needs to be positioned with respect to the ancestor CompositedLayerMapping. + // The conversion between referenceLayer and the ancestor CLM is already computed as + // offsetFromReferenceLayerToParentGraphicsLayer. + totalSquashBounds.moveBy(offsetFromReferenceLayerToParentGraphicsLayer); + IntRect squashLayerBounds = enclosingIntRect(totalSquashBounds); + IntPoint squashLayerOrigin = squashLayerBounds.location(); + LayoutSize squashLayerOriginInOwningLayerSpace = squashLayerOrigin - offsetFromReferenceLayerToParentGraphicsLayer; + + // Now that the squashing bounds are known, we can convert the RenderLayer painting offsets + // from CLM owning layer space to the squashing layer space. + // + // The painting offset we want to compute for each squashed RenderLayer is essentially the position of + // the squashed RenderLayer described w.r.t. referenceLayer's origin. For this purpose we already cached + // offsetFromSquashingCLM before, which describes where the squashed RenderLayer is located w.r.t. + // referenceLayer. So we just need to convert that point from referenceLayer space to referenceLayer + // space. This is simply done by subtracing squashLayerOriginInOwningLayerSpace, but then the offset + // overall needs to be negated because that's the direction that the painting code expects the + // offset to be. + for (size_t i = 0; i < layers.size(); ++i) { + LayoutPoint offsetFromTransformedAncestorForSquashedLayer = layers[i].renderLayer->computeOffsetFromTransformedAncestor(); + LayoutSize offsetFromSquashLayerOrigin = (offsetFromTransformedAncestorForSquashedLayer - referenceOffsetFromTransformedAncestor) - squashLayerOriginInOwningLayerSpace; + + // It is ok to repaint here, because all of the geometry needed to correctly repaint is computed by this point. + IntSize newOffsetFromRenderer = -IntSize(offsetFromSquashLayerOrigin.width().round(), offsetFromSquashLayerOrigin.height().round()); + LayoutSize subpixelAccumulation = offsetFromSquashLayerOrigin + newOffsetFromRenderer; + if (layers[i].offsetFromRendererSet && layers[i].offsetFromRenderer != newOffsetFromRenderer) { + layers[i].renderLayer->repainter().repaintIncludingNonCompositingDescendants(); + layersNeedingPaintInvalidation.append(layers[i].renderLayer); + } + layers[i].offsetFromRenderer = newOffsetFromRenderer; + layers[i].offsetFromRendererSet = true; + + layers[i].renderLayer->setSubpixelAccumulation(subpixelAccumulation); + + // FIXME: find a better design to avoid this redundant value - most likely it will make + // sense to move the paint task info into RenderLayer's m_compositingProperties. + layers[i].renderLayer->setOffsetFromSquashingLayerOrigin(layers[i].offsetFromRenderer); + } + + squashingLayer->setPosition(squashLayerBounds.location()); + squashingLayer->setSize(squashLayerBounds.size()); + + *offsetFromTransformedAncestor = referenceOffsetFromTransformedAncestor; + offsetFromTransformedAncestor->move(squashLayerOriginInOwningLayerSpace); + + for (size_t i = 0; i < layers.size(); ++i) + layers[i].localClipRectForSquashedLayer = localClipRectForSquashedLayer(referenceLayer, layers[i], layers); +} + +void CompositedLayerMapping::updateGraphicsLayerGeometry(GraphicsLayerUpdater::UpdateType updateType, const RenderLayer* compositingContainer, Vector<RenderLayer*>& layersNeedingPaintInvalidation) +{ + if (!shouldUpdateGraphicsLayer(updateType)) + return; + + // Set transform property, if it is not animating. We have to do this here because the transform + // is affected by the layer dimensions. + if (!renderer()->style()->isRunningTransformAnimationOnCompositor()) + updateTransform(renderer()->style()); + + // Set opacity, if it is not animating. + if (!renderer()->style()->isRunningOpacityAnimationOnCompositor()) + updateOpacity(renderer()->style()); + + m_owningLayer.updateDescendantDependentFlags(); + + // We compute everything relative to the enclosing compositing layer. + IntRect ancestorCompositingBounds; + if (compositingContainer) { + ASSERT(compositingContainer->hasCompositedLayerMapping()); + ancestorCompositingBounds = compositingContainer->compositedLayerMapping()->pixelSnappedCompositedBounds(); + } + + IntRect localCompositingBounds; + IntRect relativeCompositingBounds; + LayoutPoint offsetFromCompositedAncestor; + IntPoint snappedOffsetFromCompositedAncestor; + computeBoundsOfOwningLayer(compositingContainer, localCompositingBounds, relativeCompositingBounds, offsetFromCompositedAncestor, snappedOffsetFromCompositedAncestor); + + IntPoint graphicsLayerParentLocation; + computeGraphicsLayerParentLocation(compositingContainer, ancestorCompositingBounds, graphicsLayerParentLocation); + + // Might update graphicsLayerParentLocation. + updateAncestorClippingLayerGeometry(compositingContainer, snappedOffsetFromCompositedAncestor, graphicsLayerParentLocation); + + FloatSize contentsSize = relativeCompositingBounds.size(); + + updateMainGraphicsLayerGeometry(relativeCompositingBounds, localCompositingBounds, graphicsLayerParentLocation); + updateSquashingLayerGeometry(offsetFromCompositedAncestor, graphicsLayerParentLocation, m_owningLayer, m_squashedLayers, m_squashingLayer.get(), &m_squashingLayerOffsetFromTransformedAncestor, layersNeedingPaintInvalidation); + + // If we have a layer that clips children, position it. + IntRect clippingBox; + if (m_childContainmentLayer) + clippingBox = clipBox(toRenderBox(renderer())); + + updateChildContainmentLayerGeometry(clippingBox, localCompositingBounds); + updateChildTransformLayerGeometry(); + + updateMaskLayerGeometry(); + updateTransformGeometry(snappedOffsetFromCompositedAncestor, relativeCompositingBounds); + updateForegroundLayerGeometry(contentsSize, clippingBox); + updateBackgroundLayerGeometry(contentsSize); + updateReflectionLayerGeometry(layersNeedingPaintInvalidation); + updateScrollingLayerGeometry(localCompositingBounds); + updateChildClippingMaskLayerGeometry(); + + if (m_owningLayer.scrollableArea() && m_owningLayer.scrollableArea()->scrollsOverflow()) + m_owningLayer.scrollableArea()->positionOverflowControls(IntSize()); + + if (RuntimeEnabledFeatures::cssCompositingEnabled()) { + updateLayerBlendMode(renderer()->style()); + updateIsRootForIsolatedGroup(); + } + + updateContentsRect(); + updateBackgroundColor(); + updateDrawsContent(); + updateContentsOpaque(); + updateAfterWidgetResize(); + updateRenderingContext(); + updateShouldFlattenTransform(); + updateChildrenTransform(); + updateScrollParent(compositor()->acceleratedCompositingForOverflowScrollEnabled() ? m_owningLayer.scrollParent() : 0); + registerScrollingLayers(); + + updateCompositingReasons(); +} + +void CompositedLayerMapping::updateMainGraphicsLayerGeometry(const IntRect& relativeCompositingBounds, const IntRect& localCompositingBounds, IntPoint& graphicsLayerParentLocation) +{ + m_graphicsLayer->setPosition(FloatPoint(relativeCompositingBounds.location() - graphicsLayerParentLocation)); + m_graphicsLayer->setOffsetFromRenderer(toIntSize(localCompositingBounds.location())); + + FloatSize oldSize = m_graphicsLayer->size(); + const IntSize& contentsSize = relativeCompositingBounds.size(); + if (oldSize != contentsSize) + m_graphicsLayer->setSize(contentsSize); + + // m_graphicsLayer is the corresponding GraphicsLayer for this RenderLayer and its non-compositing + // descendants. So, the visibility flag for m_graphicsLayer should be true if there are any + // non-compositing visible layers. + bool contentsVisible = m_owningLayer.hasVisibleContent() || hasVisibleNonCompositingDescendant(&m_owningLayer); + if (RuntimeEnabledFeatures::overlayFullscreenVideoEnabled() && renderer()->isVideo()) { + HTMLMediaElement* mediaElement = toHTMLMediaElement(renderer()->node()); + if (mediaElement->isFullscreen()) + contentsVisible = false; + } + m_graphicsLayer->setContentsVisible(contentsVisible); + + m_graphicsLayer->setBackfaceVisibility(renderer()->style()->backfaceVisibility() == BackfaceVisibilityVisible); +} + +void CompositedLayerMapping::computeGraphicsLayerParentLocation(const RenderLayer* compositingContainer, const IntRect& ancestorCompositingBounds, IntPoint& graphicsLayerParentLocation) +{ + if (compositingContainer && compositingContainer->compositedLayerMapping()->hasClippingLayer()) { + // If the compositing ancestor has a layer to clip children, we parent in that, and therefore + // position relative to it. + IntRect clippingBox = clipBox(toRenderBox(compositingContainer->renderer())); + graphicsLayerParentLocation = clippingBox.location() + roundedIntSize(compositingContainer->subpixelAccumulation()); + } else if (compositingContainer && compositingContainer->compositedLayerMapping()->childTransformLayer()) { + // Similarly, if the compositing ancestor has a child transform layer, we parent in that, and therefore + // position relative to it. It's already taken into account the contents offset, so we do not need to here. + graphicsLayerParentLocation = roundedIntPoint(compositingContainer->subpixelAccumulation()); + } else if (compositingContainer) { + graphicsLayerParentLocation = ancestorCompositingBounds.location(); + } else { + graphicsLayerParentLocation = renderer()->view()->documentRect().location(); + } + + if (compositingContainer && compositingContainer->needsCompositedScrolling()) { + RenderBox* renderBox = toRenderBox(compositingContainer->renderer()); + IntSize scrollOffset = renderBox->scrolledContentOffset(); + IntPoint scrollOrigin(renderBox->borderLeft(), renderBox->borderTop()); + graphicsLayerParentLocation = scrollOrigin - scrollOffset; + } +} + +void CompositedLayerMapping::updateAncestorClippingLayerGeometry(const RenderLayer* compositingContainer, const IntPoint& snappedOffsetFromCompositedAncestor, IntPoint& graphicsLayerParentLocation) +{ + if (!compositingContainer || !m_ancestorClippingLayer) + return; + + // FIXME: this should use cached clip rects, but this sometimes give + // inaccurate results (and trips the ASSERTS in RenderLayerClipper). + ClipRectsContext clipRectsContext(compositingContainer, TemporaryClipRects, IgnoreOverlayScrollbarSize, IgnoreOverflowClip); + IntRect parentClipRect = pixelSnappedIntRect(m_owningLayer.clipper().backgroundClipRect(clipRectsContext).rect()); + ASSERT(parentClipRect != PaintInfo::infiniteRect()); + m_ancestorClippingLayer->setPosition(FloatPoint(parentClipRect.location() - graphicsLayerParentLocation)); + m_ancestorClippingLayer->setSize(parentClipRect.size()); + + // backgroundRect is relative to compositingContainer, so subtract snappedOffsetFromCompositedAncestor.X/snappedOffsetFromCompositedAncestor.Y to get back to local coords. + m_ancestorClippingLayer->setOffsetFromRenderer(parentClipRect.location() - snappedOffsetFromCompositedAncestor); + + // The primary layer is then parented in, and positioned relative to this clipping layer. + graphicsLayerParentLocation = parentClipRect.location(); +} + +void CompositedLayerMapping::updateChildContainmentLayerGeometry(const IntRect& clippingBox, const IntRect& localCompositingBounds) +{ + if (!m_childContainmentLayer) + return; + + m_childContainmentLayer->setPosition(FloatPoint(clippingBox.location() - localCompositingBounds.location() + roundedIntSize(m_owningLayer.subpixelAccumulation()))); + m_childContainmentLayer->setSize(clippingBox.size()); + m_childContainmentLayer->setOffsetFromRenderer(toIntSize(clippingBox.location())); + if (m_childClippingMaskLayer && !m_scrollingLayer && !renderer()->style()->clipPath()) { + m_childClippingMaskLayer->setPosition(m_childContainmentLayer->position()); + m_childClippingMaskLayer->setSize(m_childContainmentLayer->size()); + m_childClippingMaskLayer->setOffsetFromRenderer(m_childContainmentLayer->offsetFromRenderer()); + } +} + +void CompositedLayerMapping::updateChildTransformLayerGeometry() +{ + if (!m_childTransformLayer) + return; + const IntRect borderBox = toRenderBox(m_owningLayer.renderer())->pixelSnappedBorderBoxRect(); + m_childTransformLayer->setSize(borderBox.size()); + m_childTransformLayer->setPosition(FloatPoint(contentOffsetInCompositingLayer())); +} + +void CompositedLayerMapping::updateMaskLayerGeometry() +{ + if (!m_maskLayer) + return; + + if (m_maskLayer->size() != m_graphicsLayer->size()) { + m_maskLayer->setSize(m_graphicsLayer->size()); + m_maskLayer->setNeedsDisplay(); + } + m_maskLayer->setPosition(FloatPoint()); + m_maskLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer()); +} + +void CompositedLayerMapping::updateTransformGeometry(const IntPoint& snappedOffsetFromCompositedAncestor, const IntRect& relativeCompositingBounds) +{ + if (m_owningLayer.hasTransform()) { + const LayoutRect borderBox = toRenderBox(renderer())->borderBoxRect(); + + // Get layout bounds in the coords of compositingContainer to match relativeCompositingBounds. + IntRect layerBounds = pixelSnappedIntRect(toLayoutPoint(m_owningLayer.subpixelAccumulation()), borderBox.size()); + layerBounds.moveBy(snappedOffsetFromCompositedAncestor); + + // Update properties that depend on layer dimensions + FloatPoint3D transformOrigin = computeTransformOrigin(IntRect(IntPoint(), layerBounds.size())); + + // |transformOrigin| is in the local space of this layer. layerBounds - relativeCompositingBounds converts to the space of the + // compositing bounds relative to the composited ancestor. This does not apply to the z direction, since the page is 2D. + FloatPoint3D compositedTransformOrigin( + layerBounds.x() - relativeCompositingBounds.x() + transformOrigin.x(), + layerBounds.y() - relativeCompositingBounds.y() + transformOrigin.y(), + transformOrigin.z()); + m_graphicsLayer->setTransformOrigin(compositedTransformOrigin); + } else { + FloatPoint3D compositedTransformOrigin( + relativeCompositingBounds.width() * 0.5f, + relativeCompositingBounds.height() * 0.5f, + 0.f); + m_graphicsLayer->setTransformOrigin(compositedTransformOrigin); + } +} + +void CompositedLayerMapping::updateReflectionLayerGeometry(Vector<RenderLayer*>& layersNeedingPaintInvalidation) +{ + if (!m_owningLayer.reflectionInfo() || !m_owningLayer.reflectionInfo()->reflectionLayer()->hasCompositedLayerMapping()) + return; + + CompositedLayerMappingPtr reflectionCompositedLayerMapping = m_owningLayer.reflectionInfo()->reflectionLayer()->compositedLayerMapping(); + reflectionCompositedLayerMapping->updateGraphicsLayerGeometry(GraphicsLayerUpdater::ForceUpdate, &m_owningLayer, layersNeedingPaintInvalidation); +} + +void CompositedLayerMapping::updateScrollingLayerGeometry(const IntRect& localCompositingBounds) +{ + if (!m_scrollingLayer) + return; + + ASSERT(m_scrollingContentsLayer); + RenderBox* renderBox = toRenderBox(renderer()); + IntRect clientBox = enclosingIntRect(renderBox->clientBoxRect()); + + IntSize adjustedScrollOffset = m_owningLayer.scrollableArea()->adjustedScrollOffset(); + m_scrollingLayer->setPosition(FloatPoint(clientBox.location() - localCompositingBounds.location() + roundedIntSize(m_owningLayer.subpixelAccumulation()))); + m_scrollingLayer->setSize(clientBox.size()); + + IntSize oldScrollingLayerOffset = m_scrollingLayer->offsetFromRenderer(); + m_scrollingLayer->setOffsetFromRenderer(-toIntSize(clientBox.location())); + + if (m_childClippingMaskLayer && !renderer()->style()->clipPath()) { + m_childClippingMaskLayer->setPosition(m_scrollingLayer->position()); + m_childClippingMaskLayer->setSize(m_scrollingLayer->size()); + m_childClippingMaskLayer->setOffsetFromRenderer(toIntSize(clientBox.location())); + } + + bool clientBoxOffsetChanged = oldScrollingLayerOffset != m_scrollingLayer->offsetFromRenderer(); + + IntSize scrollSize(renderBox->scrollWidth(), renderBox->scrollHeight()); + if (scrollSize != m_scrollingContentsLayer->size() || clientBoxOffsetChanged) + m_scrollingContentsLayer->setNeedsDisplay(); + + IntSize scrollingContentsOffset = toIntSize(clientBox.location() - adjustedScrollOffset); + if (scrollingContentsOffset != m_scrollingContentsLayer->offsetFromRenderer() || scrollSize != m_scrollingContentsLayer->size()) { + bool coordinatorHandlesOffset = compositor()->scrollingLayerDidChange(&m_owningLayer); + m_scrollingContentsLayer->setPosition(coordinatorHandlesOffset ? FloatPoint() : FloatPoint(-adjustedScrollOffset)); + } + + m_scrollingContentsLayer->setSize(scrollSize); + // FIXME: The paint offset and the scroll offset should really be separate concepts. + m_scrollingContentsLayer->setOffsetFromRenderer(scrollingContentsOffset, GraphicsLayer::DontSetNeedsDisplay); + + if (m_foregroundLayer) { + if (m_foregroundLayer->size() != m_scrollingContentsLayer->size()) + m_foregroundLayer->setSize(m_scrollingContentsLayer->size()); + m_foregroundLayer->setNeedsDisplay(); + m_foregroundLayer->setOffsetFromRenderer(m_scrollingContentsLayer->offsetFromRenderer()); + } + + updateScrollingBlockSelection(); +} + +void CompositedLayerMapping::updateChildClippingMaskLayerGeometry() +{ + if (!m_childClippingMaskLayer || !renderer()->style()->clipPath()) + return; + RenderBox* renderBox = toRenderBox(renderer()); + IntRect clientBox = enclosingIntRect(renderBox->clientBoxRect()); + + m_childClippingMaskLayer->setPosition(m_graphicsLayer->position()); + m_childClippingMaskLayer->setSize(m_graphicsLayer->size()); + m_childClippingMaskLayer->setOffsetFromRenderer(toIntSize(clientBox.location())); + + // NOTE: also some stuff happening in updateChildContainmentLayerGeometry(). +} + +void CompositedLayerMapping::updateForegroundLayerGeometry(const FloatSize& relativeCompositingBoundsSize, const IntRect& clippingBox) +{ + if (!m_foregroundLayer) + return; + + FloatSize foregroundSize = relativeCompositingBoundsSize; + IntSize foregroundOffset = m_graphicsLayer->offsetFromRenderer(); + m_foregroundLayer->setPosition(FloatPoint()); + + if (hasClippingLayer()) { + // If we have a clipping layer (which clips descendants), then the foreground layer is a child of it, + // so that it gets correctly sorted with children. In that case, position relative to the clipping layer. + foregroundSize = FloatSize(clippingBox.size()); + foregroundOffset = toIntSize(clippingBox.location()); + } else if (m_childTransformLayer) { + // Things are different if we have a child transform layer rather + // than a clipping layer. In this case, we want to actually change + // the position of the layer (to compensate for our ancestor + // compositing layer's position) rather than leave the position the + // same and use offset-from-renderer + size to describe a clipped + // "window" onto the clipped layer. + + m_foregroundLayer->setPosition(-m_childTransformLayer->position()); + } + + if (foregroundSize != m_foregroundLayer->size()) { + m_foregroundLayer->setSize(foregroundSize); + m_foregroundLayer->setNeedsDisplay(); + } + m_foregroundLayer->setOffsetFromRenderer(foregroundOffset); + + // NOTE: there is some more configuring going on in updateScrollingLayerGeometry(). +} + +void CompositedLayerMapping::updateBackgroundLayerGeometry(const FloatSize& relativeCompositingBoundsSize) +{ + if (!m_backgroundLayer) + return; + + FloatSize backgroundSize = relativeCompositingBoundsSize; + if (backgroundLayerPaintsFixedRootBackground()) { + FrameView* frameView = toRenderView(renderer())->frameView(); + backgroundSize = frameView->visibleContentRect().size(); + } + m_backgroundLayer->setPosition(FloatPoint()); + if (backgroundSize != m_backgroundLayer->size()) { + m_backgroundLayer->setSize(backgroundSize); + m_backgroundLayer->setNeedsDisplay(); + } + m_backgroundLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer()); +} + +void CompositedLayerMapping::registerScrollingLayers() +{ + // Register fixed position layers and their containers with the scrolling coordinator. + ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer); + if (!scrollingCoordinator) + return; + + scrollingCoordinator->updateLayerPositionConstraint(&m_owningLayer); + + // Page scale is applied as a transform on the root render view layer. Because the scroll + // layer is further up in the hierarchy, we need to avoid marking the root render view + // layer as a container. + bool isContainer = m_owningLayer.hasTransform() && !m_owningLayer.isRootLayer(); + // FIXME: we should make certain that childForSuperLayers will never be the m_squashingContainmentLayer here + scrollingCoordinator->setLayerIsContainerForFixedPositionLayers(localRootForOwningLayer(), isContainer); +} + +void CompositedLayerMapping::updateInternalHierarchy() +{ + // m_foregroundLayer has to be inserted in the correct order with child layers, + // so it's not inserted here. + if (m_ancestorClippingLayer) + m_ancestorClippingLayer->removeAllChildren(); + + m_graphicsLayer->removeFromParent(); + + if (m_ancestorClippingLayer) + m_ancestorClippingLayer->addChild(m_graphicsLayer.get()); + + if (m_childContainmentLayer) + m_graphicsLayer->addChild(m_childContainmentLayer.get()); + else if (m_childTransformLayer) + m_graphicsLayer->addChild(m_childTransformLayer.get()); + + if (m_scrollingLayer) { + GraphicsLayer* superLayer = m_graphicsLayer.get(); + + if (m_childContainmentLayer) + superLayer = m_childContainmentLayer.get(); + + if (m_childTransformLayer) + superLayer = m_childTransformLayer.get(); + + superLayer->addChild(m_scrollingLayer.get()); + } + + // The clip for child layers does not include space for overflow controls, so they exist as + // siblings of the clipping layer if we have one. Normal children of this layer are set as + // children of the clipping layer. + if (m_layerForHorizontalScrollbar) + m_graphicsLayer->addChild(m_layerForHorizontalScrollbar.get()); + if (m_layerForVerticalScrollbar) + m_graphicsLayer->addChild(m_layerForVerticalScrollbar.get()); + if (m_layerForScrollCorner) + m_graphicsLayer->addChild(m_layerForScrollCorner.get()); + + // The squashing containment layer, if it exists, becomes a no-op parent. + if (m_squashingLayer) { + ASSERT(compositor()->layerSquashingEnabled()); + ASSERT((m_ancestorClippingLayer && !m_squashingContainmentLayer) || (!m_ancestorClippingLayer && m_squashingContainmentLayer)); + + if (m_squashingContainmentLayer) { + m_squashingContainmentLayer->removeAllChildren(); + m_squashingContainmentLayer->addChild(m_graphicsLayer.get()); + m_squashingContainmentLayer->addChild(m_squashingLayer.get()); + } else { + // The ancestor clipping layer is already set up and has m_graphicsLayer under it. + m_ancestorClippingLayer->addChild(m_squashingLayer.get()); + } + } +} + +void CompositedLayerMapping::updatePaintingPhases() +{ + m_graphicsLayer->setPaintingPhase(paintingPhaseForPrimaryLayer()); + if (m_scrollingContentsLayer) { + GraphicsLayerPaintingPhase paintPhase = GraphicsLayerPaintOverflowContents | GraphicsLayerPaintCompositedScroll; + if (!m_foregroundLayer) + paintPhase |= GraphicsLayerPaintForeground; + m_scrollingContentsLayer->setPaintingPhase(paintPhase); + m_scrollingBlockSelectionLayer->setPaintingPhase(paintPhase); + } +} + +void CompositedLayerMapping::updateContentsRect() +{ + m_graphicsLayer->setContentsRect(pixelSnappedIntRect(contentsBox())); +} + +void CompositedLayerMapping::updateScrollingBlockSelection() +{ + if (!m_scrollingBlockSelectionLayer) + return; + + if (!m_scrollingContentsAreEmpty) { + // In this case, the selection will be painted directly into m_scrollingContentsLayer. + m_scrollingBlockSelectionLayer->setDrawsContent(false); + return; + } + + const IntRect blockSelectionGapsBounds = m_owningLayer.blockSelectionGapsBounds(); + const bool shouldDrawContent = !blockSelectionGapsBounds.isEmpty(); + m_scrollingBlockSelectionLayer->setDrawsContent(shouldDrawContent); + if (!shouldDrawContent) + return; + + const IntPoint position = blockSelectionGapsBounds.location() + m_owningLayer.scrollableArea()->adjustedScrollOffset(); + if (m_scrollingBlockSelectionLayer->size() == blockSelectionGapsBounds.size() && m_scrollingBlockSelectionLayer->position() == position) + return; + + m_scrollingBlockSelectionLayer->setPosition(position); + m_scrollingBlockSelectionLayer->setSize(blockSelectionGapsBounds.size()); + m_scrollingBlockSelectionLayer->setOffsetFromRenderer(toIntSize(blockSelectionGapsBounds.location()), GraphicsLayer::SetNeedsDisplay); +} + +void CompositedLayerMapping::updateDrawsContent() +{ + if (m_scrollingLayer) { + // We don't have to consider overflow controls, because we know that the scrollbars are drawn elsewhere. + // m_graphicsLayer only needs backing store if the non-scrolling parts (background, outlines, borders, shadows etc) need to paint. + // m_scrollingLayer never has backing store. + // m_scrollingContentsLayer only needs backing store if the scrolled contents need to paint. + bool hasNonScrollingPaintedContent = m_owningLayer.hasVisibleContent() && m_owningLayer.hasBoxDecorationsOrBackground(); + m_graphicsLayer->setDrawsContent(hasNonScrollingPaintedContent); + + m_scrollingContentsAreEmpty = !m_owningLayer.hasVisibleContent() || !(renderer()->hasBackground() || paintsChildren()); + m_scrollingContentsLayer->setDrawsContent(!m_scrollingContentsAreEmpty); + + updateScrollingBlockSelection(); + return; + } + + bool hasPaintedContent = containsPaintedContent(); + if (hasPaintedContent && isAcceleratedCanvas(renderer())) { + CanvasRenderingContext* context = toHTMLCanvasElement(renderer()->node())->renderingContext(); + // Content layer may be null if context is lost. + if (blink::WebLayer* contentLayer = context->platformLayer()) { + Color bgColor(Color::transparent); + if (contentLayerSupportsDirectBackgroundComposition(renderer())) { + bgColor = rendererBackgroundColor(); + hasPaintedContent = false; + } + contentLayer->setBackgroundColor(bgColor.rgb()); + } + } + + // FIXME: we could refine this to only allocate backings for one of these layers if possible. + m_graphicsLayer->setDrawsContent(hasPaintedContent); + if (m_foregroundLayer) + m_foregroundLayer->setDrawsContent(hasPaintedContent); + + if (m_backgroundLayer) + m_backgroundLayer->setDrawsContent(hasPaintedContent); +} + +void CompositedLayerMapping::updateChildrenTransform() +{ + if (GraphicsLayer* childTransformLayer = layerForChildrenTransform()) { + childTransformLayer->setTransform(owningLayer().perspectiveTransform()); + childTransformLayer->setTransformOrigin(FloatPoint3D(childTransformLayer->size().width() * 0.5f, childTransformLayer->size().height() * 0.5f, 0.f)); + bool hasPerspective = false; + if (RenderStyle* style = m_owningLayer.renderer()->style()) + hasPerspective = style->hasPerspective(); + if (hasPerspective) + childTransformLayer->setShouldFlattenTransform(false); + + // Note, if the target is the scrolling layer, we need to ensure that the + // scrolling content layer doesn't flatten the transform. (It would be nice + // if we could apply transform to the scrolling content layer, but that's + // too late, we need the children transform to be applied _before_ the + // scrolling offset.) + if (childTransformLayer == m_scrollingLayer.get()) + m_scrollingContentsLayer->setShouldFlattenTransform(false); + } +} + +// Return true if the layers changed. +bool CompositedLayerMapping::updateClippingLayers(bool needsAncestorClip, bool needsDescendantClip) +{ + bool layersChanged = false; + + if (needsAncestorClip) { + if (!m_ancestorClippingLayer) { + m_ancestorClippingLayer = createGraphicsLayer(CompositingReasonLayerForAncestorClip); + m_ancestorClippingLayer->setMasksToBounds(true); + layersChanged = true; + } + } else if (m_ancestorClippingLayer) { + m_ancestorClippingLayer->removeFromParent(); + m_ancestorClippingLayer = nullptr; + layersChanged = true; + } + + if (needsDescendantClip) { + // We don't need a child containment layer if we're the main frame render view + // layer. It's redundant as the frame clip above us will handle this clipping. + if (!m_childContainmentLayer && !m_isMainFrameRenderViewLayer) { + m_childContainmentLayer = createGraphicsLayer(CompositingReasonLayerForDescendantClip); + m_childContainmentLayer->setMasksToBounds(true); + layersChanged = true; + } + } else if (hasClippingLayer()) { + m_childContainmentLayer->removeFromParent(); + m_childContainmentLayer = nullptr; + layersChanged = true; + } + + return layersChanged; +} + +bool CompositedLayerMapping::updateChildTransformLayer(bool needsChildTransformLayer) +{ + bool layersChanged = false; + + if (needsChildTransformLayer) { + if (!m_childTransformLayer) { + m_childTransformLayer = createGraphicsLayer(CompositingReasonLayerForPerspective); + m_childTransformLayer->setDrawsContent(false); + m_childTransformLayer->setShouldFlattenTransform(false); + layersChanged = true; + } + } else if (m_childTransformLayer) { + m_childTransformLayer->removeFromParent(); + m_childTransformLayer = nullptr; + layersChanged = true; + } + + return layersChanged; +} + +void CompositedLayerMapping::setBackgroundLayerPaintsFixedRootBackground(bool backgroundLayerPaintsFixedRootBackground) +{ + m_backgroundLayerPaintsFixedRootBackground = backgroundLayerPaintsFixedRootBackground; +} + +// Only a member function so it can call createGraphicsLayer. +bool CompositedLayerMapping::toggleScrollbarLayerIfNeeded(OwnPtr<GraphicsLayer>& layer, bool needsLayer, CompositingReasons reason) +{ + if (needsLayer == !!layer) + return false; + layer = needsLayer ? createGraphicsLayer(reason) : nullptr; + return true; +} + +bool CompositedLayerMapping::updateOverflowControlsLayers(bool needsHorizontalScrollbarLayer, bool needsVerticalScrollbarLayer, bool needsScrollCornerLayer) +{ + bool horizontalScrollbarLayerChanged = toggleScrollbarLayerIfNeeded(m_layerForHorizontalScrollbar, needsHorizontalScrollbarLayer, CompositingReasonLayerForHorizontalScrollbar); + bool verticalScrollbarLayerChanged = toggleScrollbarLayerIfNeeded(m_layerForVerticalScrollbar, needsVerticalScrollbarLayer, CompositingReasonLayerForVerticalScrollbar); + bool scrollCornerLayerChanged = toggleScrollbarLayerIfNeeded(m_layerForScrollCorner, needsScrollCornerLayer, CompositingReasonLayerForScrollCorner); + + if (ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer)) { + if (horizontalScrollbarLayerChanged) + scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_owningLayer.scrollableArea(), HorizontalScrollbar); + if (verticalScrollbarLayerChanged) + scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_owningLayer.scrollableArea(), VerticalScrollbar); + } + + return horizontalScrollbarLayerChanged || verticalScrollbarLayerChanged || scrollCornerLayerChanged; +} + +void CompositedLayerMapping::positionOverflowControlsLayers(const IntSize& offsetFromRoot) +{ + IntSize offsetFromRenderer = m_graphicsLayer->offsetFromRenderer() - roundedIntSize(m_owningLayer.subpixelAccumulation()); + if (GraphicsLayer* layer = layerForHorizontalScrollbar()) { + Scrollbar* hBar = m_owningLayer.scrollableArea()->horizontalScrollbar(); + if (hBar) { + layer->setPosition(hBar->frameRect().location() - offsetFromRoot - offsetFromRenderer); + layer->setSize(hBar->frameRect().size()); + if (layer->hasContentsLayer()) + layer->setContentsRect(IntRect(IntPoint(), hBar->frameRect().size())); + } + layer->setDrawsContent(hBar && !layer->hasContentsLayer()); + } + + if (GraphicsLayer* layer = layerForVerticalScrollbar()) { + Scrollbar* vBar = m_owningLayer.scrollableArea()->verticalScrollbar(); + if (vBar) { + layer->setPosition(vBar->frameRect().location() - offsetFromRoot - offsetFromRenderer); + layer->setSize(vBar->frameRect().size()); + if (layer->hasContentsLayer()) + layer->setContentsRect(IntRect(IntPoint(), vBar->frameRect().size())); + } + layer->setDrawsContent(vBar && !layer->hasContentsLayer()); + } + + if (GraphicsLayer* layer = layerForScrollCorner()) { + const LayoutRect& scrollCornerAndResizer = m_owningLayer.scrollableArea()->scrollCornerAndResizerRect(); + layer->setPosition(scrollCornerAndResizer.location() - offsetFromRenderer); + layer->setSize(scrollCornerAndResizer.size()); + layer->setDrawsContent(!scrollCornerAndResizer.isEmpty()); + } +} + +bool CompositedLayerMapping::hasUnpositionedOverflowControlsLayers() const +{ + if (GraphicsLayer* layer = layerForHorizontalScrollbar()) { + if (!layer->drawsContent()) + return true; + } + + if (GraphicsLayer* layer = layerForVerticalScrollbar()) { + if (!layer->drawsContent()) + return true; + } + + if (GraphicsLayer* layer = layerForScrollCorner()) { + if (!layer->drawsContent()) + return true; + } + + return false; +} + +enum ApplyToGraphicsLayersModeFlags { + ApplyToCoreLayers = (1 << 0), + ApplyToSquashingLayer = (1 << 1), + ApplyToScrollbarLayers = (1 << 2), + ApplyToBackgroundLayer = (1 << 3), + ApplyToMaskLayers = (1 << 4), + ApplyToContentLayers = (1 << 5), + ApplyToAllGraphicsLayers = (ApplyToSquashingLayer | ApplyToScrollbarLayers | ApplyToBackgroundLayer | ApplyToMaskLayers | ApplyToCoreLayers | ApplyToContentLayers) +}; +typedef unsigned ApplyToGraphicsLayersMode; + +template <typename Func> +static void ApplyToGraphicsLayers(const CompositedLayerMapping* mapping, const Func& f, ApplyToGraphicsLayersMode mode) +{ + ASSERT(mode); + + if ((mode & ApplyToCoreLayers) && mapping->squashingContainmentLayer()) + f(mapping->squashingContainmentLayer()); + if ((mode & ApplyToCoreLayers) && mapping->childTransformLayer()) + f(mapping->childTransformLayer()); + if ((mode & ApplyToCoreLayers) && mapping->ancestorClippingLayer()) + f(mapping->ancestorClippingLayer()); + if (((mode & ApplyToCoreLayers) || (mode & ApplyToContentLayers)) && mapping->mainGraphicsLayer()) + f(mapping->mainGraphicsLayer()); + if ((mode & ApplyToCoreLayers) && mapping->clippingLayer()) + f(mapping->clippingLayer()); + if ((mode & ApplyToCoreLayers) && mapping->scrollingLayer()) + f(mapping->scrollingLayer()); + if (((mode & ApplyToCoreLayers) || (mode & ApplyToContentLayers)) && mapping->scrollingContentsLayer()) + f(mapping->scrollingContentsLayer()); + if (((mode & ApplyToCoreLayers) || (mode & ApplyToContentLayers)) && mapping->foregroundLayer()) + f(mapping->foregroundLayer()); + + if ((mode & ApplyToSquashingLayer) && mapping->squashingLayer()) + f(mapping->squashingLayer()); + + if (((mode & ApplyToMaskLayers) || (mode & ApplyToContentLayers)) && mapping->maskLayer()) + f(mapping->maskLayer()); + if (((mode & ApplyToMaskLayers) || (mode & ApplyToContentLayers)) && mapping->childClippingMaskLayer()) + f(mapping->childClippingMaskLayer()); + + if (((mode & ApplyToBackgroundLayer) || (mode & ApplyToContentLayers)) && mapping->backgroundLayer()) + f(mapping->backgroundLayer()); + + if ((mode & ApplyToScrollbarLayers) && mapping->layerForHorizontalScrollbar()) + f(mapping->layerForHorizontalScrollbar()); + if ((mode & ApplyToScrollbarLayers) && mapping->layerForVerticalScrollbar()) + f(mapping->layerForVerticalScrollbar()); + if ((mode & ApplyToScrollbarLayers) && mapping->layerForScrollCorner()) + f(mapping->layerForScrollCorner()); +} + +struct UpdateRenderingContextFunctor { + void operator() (GraphicsLayer* layer) const { layer->setRenderingContext(renderingContext); } + int renderingContext; +}; + +void CompositedLayerMapping::updateRenderingContext() +{ + // All layers but the squashing layer (which contains 'alien' content) should be included in this + // rendering context. + int id = 0; + + // NB, it is illegal at this point to query an ancestor's compositing state. Some compositing + // reasons depend on the compositing state of ancestors. So if we want a rendering context id + // for the context root, we cannot ask for the id of its associated WebLayer now; it may not have + // one yet. We could do a second past after doing the compositing updates to get these ids, + // but this would actually be harmful. We do not want to attach any semantic meaning to + // the context id other than the fact that they group a number of layers together for the + // sake of 3d sorting. So instead we will ask the compositor to vend us an arbitrary, but + // consistent id. + if (RenderLayer* root = m_owningLayer.renderingContextRoot()) { + if (Node* node = root->renderer()->node()) + id = static_cast<int>(WTF::PtrHash<Node*>::hash(node)); + } + + UpdateRenderingContextFunctor functor = { id }; + ApplyToGraphicsLayersMode mode = ApplyToAllGraphicsLayers & ~ApplyToSquashingLayer; + ApplyToGraphicsLayers<UpdateRenderingContextFunctor>(this, functor, mode); +} + +struct UpdateShouldFlattenTransformFunctor { + void operator() (GraphicsLayer* layer) const { layer->setShouldFlattenTransform(shouldFlatten); } + bool shouldFlatten; +}; + +void CompositedLayerMapping::updateShouldFlattenTransform() +{ + // All CLM-managed layers that could affect a descendant layer should update their + // should-flatten-transform value (the other layers' transforms don't matter here). + UpdateShouldFlattenTransformFunctor functor = { !m_owningLayer.shouldPreserve3D() }; + ApplyToGraphicsLayersMode mode = ApplyToCoreLayers; + ApplyToGraphicsLayers(this, functor, mode); +} + +bool CompositedLayerMapping::updateForegroundLayer(bool needsForegroundLayer) +{ + bool layerChanged = false; + if (needsForegroundLayer) { + if (!m_foregroundLayer) { + m_foregroundLayer = createGraphicsLayer(CompositingReasonLayerForForeground); + m_foregroundLayer->setDrawsContent(true); + m_foregroundLayer->setPaintingPhase(GraphicsLayerPaintForeground); + layerChanged = true; + } + } else if (m_foregroundLayer) { + FloatRect repaintRect(FloatPoint(), m_foregroundLayer->size()); + m_foregroundLayer->removeFromParent(); + m_foregroundLayer = nullptr; + layerChanged = true; + } + + return layerChanged; +} + +bool CompositedLayerMapping::updateBackgroundLayer(bool needsBackgroundLayer) +{ + bool layerChanged = false; + if (needsBackgroundLayer) { + if (!m_backgroundLayer) { + m_backgroundLayer = createGraphicsLayer(CompositingReasonLayerForBackground); + m_backgroundLayer->setDrawsContent(true); + m_backgroundLayer->setTransformOrigin(FloatPoint3D()); + m_backgroundLayer->setPaintingPhase(GraphicsLayerPaintBackground); +#if !OS(ANDROID) + m_backgroundLayer->contentLayer()->setDrawCheckerboardForMissingTiles(true); + m_graphicsLayer->contentLayer()->setDrawCheckerboardForMissingTiles(false); +#endif + layerChanged = true; + } + } else { + if (m_backgroundLayer) { + m_backgroundLayer->removeFromParent(); + m_backgroundLayer = nullptr; +#if !OS(ANDROID) + m_graphicsLayer->contentLayer()->setDrawCheckerboardForMissingTiles(true); +#endif + layerChanged = true; + } + } + + if (layerChanged && !m_owningLayer.renderer()->documentBeingDestroyed()) + compositor()->rootFixedBackgroundsChanged(); + + return layerChanged; +} + +bool CompositedLayerMapping::updateMaskLayer(bool needsMaskLayer) +{ + bool layerChanged = false; + if (needsMaskLayer) { + if (!m_maskLayer) { + m_maskLayer = createGraphicsLayer(CompositingReasonLayerForMask); + m_maskLayer->setDrawsContent(true); + m_maskLayer->setPaintingPhase(GraphicsLayerPaintMask); + layerChanged = true; + } + } else if (m_maskLayer) { + m_maskLayer = nullptr; + layerChanged = true; + } + + return layerChanged; +} + +bool CompositedLayerMapping::updateClippingMaskLayers(bool needsChildClippingMaskLayer) +{ + bool layerChanged = false; + if (needsChildClippingMaskLayer) { + if (!m_childClippingMaskLayer) { + m_childClippingMaskLayer = createGraphicsLayer(CompositingReasonLayerForClippingMask); + m_childClippingMaskLayer->setDrawsContent(true); + m_childClippingMaskLayer->setPaintingPhase(GraphicsLayerPaintChildClippingMask); + layerChanged = true; + } + } else if (m_childClippingMaskLayer) { + m_childClippingMaskLayer = nullptr; + layerChanged = true; + } + return layerChanged; +} + +bool CompositedLayerMapping::updateScrollingLayers(bool needsScrollingLayers) +{ + ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer); + + bool layerChanged = false; + if (needsScrollingLayers) { + if (!m_scrollingLayer) { + // Outer layer which corresponds with the scroll view. + m_scrollingLayer = createGraphicsLayer(CompositingReasonLayerForScrollingContainer); + m_scrollingLayer->setDrawsContent(false); + m_scrollingLayer->setMasksToBounds(true); + + // Inner layer which renders the content that scrolls. + m_scrollingContentsLayer = createGraphicsLayer(CompositingReasonLayerForScrollingContents); + m_scrollingContentsLayer->setDrawsContent(true); + m_scrollingLayer->addChild(m_scrollingContentsLayer.get()); + + m_scrollingBlockSelectionLayer = createGraphicsLayer(CompositingReasonLayerForScrollingBlockSelection); + m_scrollingBlockSelectionLayer->setDrawsContent(true); + m_scrollingContentsLayer->addChild(m_scrollingBlockSelectionLayer.get()); + + layerChanged = true; + if (scrollingCoordinator) + scrollingCoordinator->scrollableAreaScrollLayerDidChange(m_owningLayer.scrollableArea()); + } + } else if (m_scrollingLayer) { + m_scrollingLayer = nullptr; + m_scrollingContentsLayer = nullptr; + m_scrollingBlockSelectionLayer = nullptr; + layerChanged = true; + if (scrollingCoordinator) + scrollingCoordinator->scrollableAreaScrollLayerDidChange(m_owningLayer.scrollableArea()); + } + + return layerChanged; +} + +static void updateScrollParentForGraphicsLayer(GraphicsLayer* layer, GraphicsLayer* topmostLayer, RenderLayer* scrollParent, ScrollingCoordinator* scrollingCoordinator) +{ + if (!layer) + return; + + // Only the topmost layer has a scroll parent. All other layers have a null scroll parent. + if (layer != topmostLayer) + scrollParent = 0; + + scrollingCoordinator->updateScrollParentForGraphicsLayer(layer, scrollParent); +} + +void CompositedLayerMapping::updateScrollParent(RenderLayer* scrollParent) +{ + if (ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer)) { + GraphicsLayer* topmostLayer = childForSuperlayers(); + updateScrollParentForGraphicsLayer(m_squashingContainmentLayer.get(), topmostLayer, scrollParent, scrollingCoordinator); + updateScrollParentForGraphicsLayer(m_ancestorClippingLayer.get(), topmostLayer, scrollParent, scrollingCoordinator); + updateScrollParentForGraphicsLayer(m_graphicsLayer.get(), topmostLayer, scrollParent, scrollingCoordinator); + } +} + +void CompositedLayerMapping::updateClipParent(RenderLayer* clipParent) +{ + if (ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer)) + scrollingCoordinator->updateClipParentForGraphicsLayer(m_graphicsLayer.get(), clipParent); +} + +bool CompositedLayerMapping::updateSquashingLayers(bool needsSquashingLayers) +{ + bool layersChanged = false; + + if (needsSquashingLayers) { + ASSERT(compositor()->layerSquashingEnabled()); + + if (!m_squashingLayer) { + m_squashingLayer = createGraphicsLayer(CompositingReasonLayerForSquashingContents); + m_squashingLayer->setDrawsContent(true); + layersChanged = true; + } + + if (m_ancestorClippingLayer) { + if (m_squashingContainmentLayer) { + m_squashingContainmentLayer->removeFromParent(); + m_squashingContainmentLayer = nullptr; + layersChanged = true; + } + } else { + if (!m_squashingContainmentLayer) { + m_squashingContainmentLayer = createGraphicsLayer(CompositingReasonLayerForSquashingContainer); + layersChanged = true; + } + } + + ASSERT((m_ancestorClippingLayer && !m_squashingContainmentLayer) || (!m_ancestorClippingLayer && m_squashingContainmentLayer)); + ASSERT(m_squashingLayer); + } else { + if (m_squashingLayer) { + m_squashingLayer->removeFromParent(); + m_squashingLayer = nullptr; + layersChanged = true; + } + if (m_squashingContainmentLayer) { + m_squashingContainmentLayer->removeFromParent(); + m_squashingContainmentLayer = nullptr; + layersChanged = true; + } + ASSERT(!m_squashingLayer && !m_squashingContainmentLayer); + } + + return layersChanged; +} + +GraphicsLayerPaintingPhase CompositedLayerMapping::paintingPhaseForPrimaryLayer() const +{ + unsigned phase = 0; + if (!m_backgroundLayer) + phase |= GraphicsLayerPaintBackground; + if (!m_foregroundLayer) + phase |= GraphicsLayerPaintForeground; + if (!m_maskLayer) + phase |= GraphicsLayerPaintMask; + + if (m_scrollingContentsLayer) { + phase &= ~GraphicsLayerPaintForeground; + phase |= GraphicsLayerPaintCompositedScroll; + } + + return static_cast<GraphicsLayerPaintingPhase>(phase); +} + +float CompositedLayerMapping::compositingOpacity(float rendererOpacity) const +{ + float finalOpacity = rendererOpacity; + + for (RenderLayer* curr = m_owningLayer.parent(); curr; curr = curr->parent()) { + // We only care about parents that are stacking contexts. + // Recall that opacity creates stacking context. + if (!curr->stackingNode()->isStackingContext()) + continue; + + // If we found a composited layer, regardless of whether it actually + // paints into it, we want to compute opacity relative to it. So we can + // break here. + // + // FIXME: with grouped backings, a composited descendant will have to + // continue past the grouped (squashed) layers that its parents may + // contribute to. This whole confusion can be avoided by specifying + // explicitly the composited ancestor where we would stop accumulating + // opacity. + if (curr->compositingState() == PaintsIntoOwnBacking || curr->compositingState() == HasOwnBackingButPaintsIntoAncestor) + break; + + finalOpacity *= curr->renderer()->opacity(); + } + + return finalOpacity; +} + +Color CompositedLayerMapping::rendererBackgroundColor() const +{ + RenderObject* backgroundRenderer = renderer(); + if (backgroundRenderer->isDocumentElement()) + backgroundRenderer = backgroundRenderer->rendererForRootBackground(); + + return backgroundRenderer->resolveColor(CSSPropertyBackgroundColor); +} + +void CompositedLayerMapping::updateBackgroundColor() +{ + m_graphicsLayer->setBackgroundColor(rendererBackgroundColor()); +} + +bool CompositedLayerMapping::paintsChildren() const +{ + if (m_owningLayer.hasVisibleContent() && m_owningLayer.hasNonEmptyChildRenderers()) + return true; + + if (hasVisibleNonCompositingDescendant(&m_owningLayer)) + return true; + + return false; +} + +static bool isCompositedPlugin(RenderObject* renderer) +{ + return renderer->isEmbeddedObject() && toRenderEmbeddedObject(renderer)->requiresAcceleratedCompositing(); +} + +bool CompositedLayerMapping::hasVisibleNonCompositingDescendant(RenderLayer* parent) +{ + if (!parent->hasVisibleDescendant()) + return false; + + // FIXME: We shouldn't be called with a stale z-order lists. See bug 85512. + parent->stackingNode()->updateLayerListsIfNeeded(); + +#if ASSERT_ENABLED + LayerListMutationDetector mutationChecker(parent->stackingNode()); +#endif + + RenderLayerStackingNodeIterator normalFlowIterator(*parent->stackingNode(), AllChildren); + while (RenderLayerStackingNode* curNode = normalFlowIterator.next()) { + RenderLayer* curLayer = curNode->layer(); + if (curLayer->hasCompositedLayerMapping()) + continue; + if (curLayer->hasVisibleContent() || hasVisibleNonCompositingDescendant(curLayer)) + return true; + } + + return false; +} + +bool CompositedLayerMapping::containsPaintedContent() const +{ + if (paintsIntoCompositedAncestor() || m_owningLayer.isReflection()) + return false; + + if (isDirectlyCompositedImage()) + return false; + + RenderObject* renderObject = renderer(); + // FIXME: we could optimize cases where the image, video or canvas is known to fill the border box entirely, + // and set background color on the layer in that case, instead of allocating backing store and painting. + if (renderObject->isVideo() && toRenderVideo(renderer())->shouldDisplayVideo()) + return m_owningLayer.hasBoxDecorationsOrBackground(); + + if (m_owningLayer.hasVisibleBoxDecorations()) + return true; + + if (renderObject->hasMask()) // masks require special treatment + return true; + + if (renderObject->isReplaced() && !isCompositedPlugin(renderObject)) + return true; + + if (renderObject->isRenderRegion()) + 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() ? renderObject->document().documentElement()->renderer() : 0; + // Reject anything that has a border, a border-radius or outline, + // or is not a simple background (no background, or solid color). + if (rootObject && hasBoxDecorationsOrBackgroundImage(rootObject->style())) + return true; + + // Now look at the body's renderer. + HTMLElement* body = renderObject->document().body(); + RenderObject* bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0; + if (bodyObject && hasBoxDecorationsOrBackgroundImage(bodyObject->style())) + return true; + } + + // FIXME: it's O(n^2). A better solution is needed. + return paintsChildren(); +} + +// An image can be directly compositing if it's the sole content of the layer, and has no box decorations +// that require painting. Direct compositing saves backing store. +bool CompositedLayerMapping::isDirectlyCompositedImage() const +{ + RenderObject* renderObject = renderer(); + + if (!renderObject->isImage() || m_owningLayer.hasBoxDecorationsOrBackground() || renderObject->hasClip()) + return false; + + RenderImage* imageRenderer = toRenderImage(renderObject); + if (ImageResource* cachedImage = imageRenderer->cachedImage()) { + if (!cachedImage->hasImage()) + return false; + + Image* image = cachedImage->imageForRenderer(imageRenderer); + return image->isBitmapImage(); + } + + return false; +} + +void CompositedLayerMapping::contentChanged(ContentChangeType changeType) +{ + if ((changeType == ImageChanged) && isDirectlyCompositedImage()) { + updateImageContents(); + return; + } + + if ((changeType == CanvasChanged || changeType == CanvasPixelsChanged) && isAcceleratedCanvas(renderer())) { + m_graphicsLayer->setContentsNeedsDisplay(); + return; + } +} + +void CompositedLayerMapping::updateImageContents() +{ + ASSERT(renderer()->isImage()); + RenderImage* imageRenderer = toRenderImage(renderer()); + + ImageResource* cachedImage = imageRenderer->cachedImage(); + if (!cachedImage) + return; + + Image* image = cachedImage->imageForRenderer(imageRenderer); + if (!image) + return; + + // We have to wait until the image is fully loaded before setting it on the layer. + if (!cachedImage->isLoaded()) + return; + + // This is a no-op if the layer doesn't have an inner layer for the image. + m_graphicsLayer->setContentsToImage(image); + updateDrawsContent(); + + // Image animation is "lazy", in that it automatically stops unless someone is drawing + // the image. So we have to kick the animation each time; this has the downside that the + // image will keep animating, even if its layer is not visible. + image->startAnimation(); +} + +FloatPoint3D CompositedLayerMapping::computeTransformOrigin(const IntRect& borderBox) const +{ + RenderStyle* style = renderer()->style(); + + FloatPoint3D origin; + origin.setX(floatValueForLength(style->transformOriginX(), borderBox.width())); + origin.setY(floatValueForLength(style->transformOriginY(), borderBox.height())); + origin.setZ(style->transformOriginZ()); + + return origin; +} + +// Return the offset from the top-left of this compositing layer at which the renderer's contents are painted. +LayoutSize CompositedLayerMapping::contentOffsetInCompositingLayer() const +{ + return LayoutSize(-m_compositedBounds.x(), -m_compositedBounds.y()); +} + +LayoutRect CompositedLayerMapping::contentsBox() const +{ + LayoutRect contentsBox = contentsRect(renderer()); + contentsBox.move(contentOffsetInCompositingLayer()); + return contentsBox; +} + +GraphicsLayer* CompositedLayerMapping::parentForSublayers() const +{ + if (m_scrollingBlockSelectionLayer) + return m_scrollingBlockSelectionLayer.get(); + + if (m_scrollingContentsLayer) + return m_scrollingContentsLayer.get(); + + if (m_childContainmentLayer) + return m_childContainmentLayer.get(); + + if (m_childTransformLayer) + return m_childTransformLayer.get(); + + return m_graphicsLayer.get(); +} + +GraphicsLayer* CompositedLayerMapping::localRootForOwningLayer() const +{ + if (m_ancestorClippingLayer) + return m_ancestorClippingLayer.get(); + + return m_graphicsLayer.get(); +} + +GraphicsLayer* CompositedLayerMapping::childForSuperlayers() const +{ + if (m_squashingContainmentLayer) + return m_squashingContainmentLayer.get(); + + return localRootForOwningLayer(); +} + +GraphicsLayer* CompositedLayerMapping::layerForChildrenTransform() const +{ + if (GraphicsLayer* clipLayer = clippingLayer()) + return clipLayer; + if (m_scrollingLayer) + return m_scrollingLayer.get(); + return m_childTransformLayer.get(); +} + +bool CompositedLayerMapping::updateRequiresOwnBackingStoreForAncestorReasons(const RenderLayer* compositingAncestorLayer) +{ + unsigned previousRequiresOwnBackingStoreForAncestorReasons = m_requiresOwnBackingStoreForAncestorReasons; + bool previousPaintsIntoCompositedAncestor = paintsIntoCompositedAncestor(); + bool canPaintIntoAncestor = compositingAncestorLayer + && (compositingAncestorLayer->compositedLayerMapping()->mainGraphicsLayer()->drawsContent() + || compositingAncestorLayer->compositedLayerMapping()->paintsIntoCompositedAncestor()); + m_requiresOwnBackingStoreForAncestorReasons = !canPaintIntoAncestor; + + if (paintsIntoCompositedAncestor() != previousPaintsIntoCompositedAncestor) + paintsIntoCompositedAncestorChanged(); + return m_requiresOwnBackingStoreForAncestorReasons != previousRequiresOwnBackingStoreForAncestorReasons; +} + +bool CompositedLayerMapping::updateRequiresOwnBackingStoreForIntrinsicReasons() +{ + unsigned previousRequiresOwnBackingStoreForIntrinsicReasons = m_requiresOwnBackingStoreForIntrinsicReasons; + bool previousPaintsIntoCompositedAncestor = paintsIntoCompositedAncestor(); + RenderObject* renderer = m_owningLayer.renderer(); + m_requiresOwnBackingStoreForIntrinsicReasons = m_owningLayer.isRootLayer() + || (m_owningLayer.compositingReasons() & CompositingReasonComboReasonsThatRequireOwnBacking) + || m_owningLayer.transform() + || m_owningLayer.clipsCompositingDescendantsWithBorderRadius() // FIXME: Revisit this if the paintsIntoCompositedAncestor state is removed. + || renderer->isTransparent() + || renderer->hasMask() + || renderer->hasReflection() + || renderer->hasFilter(); + + if (paintsIntoCompositedAncestor() != previousPaintsIntoCompositedAncestor) + paintsIntoCompositedAncestorChanged(); + return m_requiresOwnBackingStoreForIntrinsicReasons != previousRequiresOwnBackingStoreForIntrinsicReasons; +} + +void CompositedLayerMapping::paintsIntoCompositedAncestorChanged() +{ + // The answer to paintsIntoCompositedAncestor() affects cached clip rects, so when + // it changes we have to clear clip rects on descendants. + m_owningLayer.clipper().clearClipRectsIncludingDescendants(PaintingClipRects); + m_owningLayer.repainter().computeRepaintRectsIncludingNonCompositingDescendants(); + + compositor()->repaintInCompositedAncestor(&m_owningLayer, compositedBounds()); +} + +void CompositedLayerMapping::setBlendMode(blink::WebBlendMode blendMode) +{ + if (m_ancestorClippingLayer) { + m_ancestorClippingLayer->setBlendMode(blendMode); + m_graphicsLayer->setBlendMode(blink::WebBlendModeNormal); + } else { + m_graphicsLayer->setBlendMode(blendMode); + } +} + +GraphicsLayerUpdater::UpdateType CompositedLayerMapping::updateTypeForChildren(GraphicsLayerUpdater::UpdateType updateType) const +{ + if (m_pendingUpdateScope >= GraphicsLayerUpdateSubtree) + return GraphicsLayerUpdater::ForceUpdate; + return updateType; +} + +struct SetContentsNeedsDisplayFunctor { + void operator() (GraphicsLayer* layer) const + { + if (layer->drawsContent()) + layer->setNeedsDisplay(); + } +}; + +void CompositedLayerMapping::setSquashingContentsNeedDisplay() +{ + ApplyToGraphicsLayers(this, SetContentsNeedsDisplayFunctor(), ApplyToSquashingLayer); +} + +void CompositedLayerMapping::setContentsNeedDisplay() +{ + // FIXME: need to split out repaints for the background. + ASSERT(!paintsIntoCompositedAncestor()); + ApplyToGraphicsLayers(this, SetContentsNeedsDisplayFunctor(), ApplyToContentLayers); +} + +struct SetContentsNeedsDisplayInRectFunctor { + void operator() (GraphicsLayer* layer) const + { + if (layer->drawsContent()) { + IntRect layerDirtyRect = r; + layerDirtyRect.move(-layer->offsetFromRenderer()); + layer->setNeedsDisplayInRect(layerDirtyRect); + } + } + + IntRect r; +}; + +// r is in the coordinate space of the layer's render object +void CompositedLayerMapping::setContentsNeedDisplayInRect(const IntRect& r) +{ + // FIXME: need to split out repaints for the background. + ASSERT(!paintsIntoCompositedAncestor()); + SetContentsNeedsDisplayInRectFunctor functor = { r }; + ApplyToGraphicsLayers(this, functor, ApplyToContentLayers); +} + +const GraphicsLayerPaintInfo* CompositedLayerMapping::containingSquashedLayer(const RenderObject* renderObject, const Vector<GraphicsLayerPaintInfo>& layers) +{ + for (size_t i = 0; i < layers.size(); ++i) { + if (renderObject->isDescendantOf(layers[i].renderLayer->renderer())) { + return &layers[i]; + break; + } + } + return 0; +} + +const GraphicsLayerPaintInfo* CompositedLayerMapping::containingSquashedLayer(const RenderObject* renderObject) +{ + return CompositedLayerMapping::containingSquashedLayer(renderObject, m_squashedLayers); +} + +IntRect CompositedLayerMapping::localClipRectForSquashedLayer(const RenderLayer& referenceLayer, const GraphicsLayerPaintInfo& paintInfo, const Vector<GraphicsLayerPaintInfo>& layers) +{ + const RenderObject* clippingContainer = paintInfo.renderLayer->renderer()->clippingContainer(); + if (clippingContainer == referenceLayer.renderer()->clippingContainer()) + return PaintInfo::infiniteRect(); + + ASSERT(clippingContainer); + + const GraphicsLayerPaintInfo* ancestorPaintInfo = containingSquashedLayer(clippingContainer, layers); + // Must be there, otherwise CompositingLayerAssigner::canSquashIntoCurrentSquashingOwner would have disallowed squashing. + ASSERT(ancestorPaintInfo); + + // FIXME: this is a potential performance issue. We shoudl consider caching these clip rects or otherwise optimizing. + ClipRectsContext clipRectsContext(ancestorPaintInfo->renderLayer, TemporaryClipRects); + IntRect parentClipRect = pixelSnappedIntRect(paintInfo.renderLayer->clipper().backgroundClipRect(clipRectsContext).rect()); + ASSERT(parentClipRect != PaintInfo::infiniteRect()); + + // Convert from ancestor to local coordinates. + IntSize ancestorToLocalOffset = paintInfo.offsetFromRenderer - ancestorPaintInfo->offsetFromRenderer; + parentClipRect.move(ancestorToLocalOffset); + return parentClipRect; +} + +void CompositedLayerMapping::doPaintTask(GraphicsLayerPaintInfo& paintInfo, GraphicsContext* context, + const IntRect& clip) // In the coords of rootLayer. +{ + if (paintsIntoCompositedAncestor()) { + ASSERT_NOT_REACHED(); + return; + } + + FontCachePurgePreventer fontCachePurgePreventer; + + PaintLayerFlags paintFlags = 0; + if (paintInfo.paintingPhase & GraphicsLayerPaintBackground) + paintFlags |= PaintLayerPaintingCompositingBackgroundPhase; + if (paintInfo.paintingPhase & GraphicsLayerPaintForeground) + paintFlags |= PaintLayerPaintingCompositingForegroundPhase; + if (paintInfo.paintingPhase & GraphicsLayerPaintMask) + paintFlags |= PaintLayerPaintingCompositingMaskPhase; + if (paintInfo.paintingPhase & GraphicsLayerPaintChildClippingMask) + paintFlags |= PaintLayerPaintingChildClippingMaskPhase; + if (paintInfo.paintingPhase & GraphicsLayerPaintOverflowContents) + paintFlags |= PaintLayerPaintingOverflowContents; + if (paintInfo.paintingPhase & GraphicsLayerPaintCompositedScroll) + paintFlags |= PaintLayerPaintingCompositingScrollingPhase; + + if (paintInfo.isBackgroundLayer) + paintFlags |= (PaintLayerPaintingRootBackgroundOnly | PaintLayerPaintingCompositingForegroundPhase); // Need PaintLayerPaintingCompositingForegroundPhase to walk child layers. + else if (compositor()->fixedRootBackgroundLayer()) + paintFlags |= PaintLayerPaintingSkipRootBackground; + + // Note carefully: in theory it is appropriate to invoke context->save() here + // and restore the context after painting. For efficiency, we are assuming that + // it is equivalent to manually undo this offset translation, which means we are + // assuming that the context's space was not affected by the RenderLayer + // painting code. + + IntSize offset = paintInfo.offsetFromRenderer; + context->translate(-offset.width(), -offset.height()); + + // The dirtyRect is in the coords of the painting root. + IntRect dirtyRect(clip); + dirtyRect.move(offset); + + if (!(paintInfo.paintingPhase & GraphicsLayerPaintOverflowContents)) { + LayoutRect bounds = paintInfo.compositedBounds; + bounds.move(paintInfo.renderLayer->subpixelAccumulation()); + dirtyRect.intersect(pixelSnappedIntRect(bounds)); + } else { + dirtyRect.move(roundedIntSize(paintInfo.renderLayer->subpixelAccumulation())); + } + +#ifndef NDEBUG + paintInfo.renderLayer->renderer()->assertSubtreeIsLaidOut(); +#endif + + if (paintInfo.renderLayer->compositingState() != PaintsIntoGroupedBacking) { + // FIXME: GraphicsLayers need a way to split for RenderRegions. + LayerPaintingInfo paintingInfo(paintInfo.renderLayer, dirtyRect, PaintBehaviorNormal, paintInfo.renderLayer->subpixelAccumulation()); + paintInfo.renderLayer->paintLayerContents(context, paintingInfo, paintFlags); + + ASSERT(!paintInfo.isBackgroundLayer || paintFlags & PaintLayerPaintingRootBackgroundOnly); + + if (paintInfo.renderLayer->containsDirtyOverlayScrollbars()) + paintInfo.renderLayer->paintLayerContents(context, paintingInfo, paintFlags | PaintLayerPaintingOverlayScrollbars); + } else { + ASSERT(compositor()->layerSquashingEnabled()); + LayerPaintingInfo paintingInfo(paintInfo.renderLayer, dirtyRect, PaintBehaviorNormal, paintInfo.renderLayer->subpixelAccumulation()); + + // RenderLayer::paintLayer assumes that the caller clips to the passed rect. Squashed layers need to do this clipping in software, + // since there is no graphics layer to clip them precisely. Furthermore, in some cases we squash layers that need clipping in software + // from clipping ancestors (see CompositedLayerMapping::localClipRectForSquashedLayer()). + context->save(); + dirtyRect.intersect(paintInfo.localClipRectForSquashedLayer); + context->clip(dirtyRect); + paintInfo.renderLayer->paintLayer(context, paintingInfo, paintFlags); + context->restore(); + } + + ASSERT(!paintInfo.renderLayer->usedTransparency()); + + // Manually restore the context to its original state by applying the opposite translation. + context->translate(offset.width(), offset.height()); +} + +static void paintScrollbar(Scrollbar* scrollbar, GraphicsContext& context, const IntRect& clip) +{ + if (!scrollbar) + return; + + context.save(); + const IntRect& scrollbarRect = scrollbar->frameRect(); + context.translate(-scrollbarRect.x(), -scrollbarRect.y()); + IntRect transformedClip = clip; + transformedClip.moveBy(scrollbarRect.location()); + scrollbar->paint(&context, transformedClip); + context.restore(); +} + +// Up-call from compositing layer drawing callback. +void CompositedLayerMapping::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& context, GraphicsLayerPaintingPhase paintingPhase, const IntRect& clip) +{ + // https://code.google.com/p/chromium/issues/detail?id=343772 + DisableCompositingQueryAsserts disabler; +#ifndef NDEBUG + // FIXME: once the state machine is ready, this can be removed and we can refer to that instead. + if (Page* page = renderer()->frame()->page()) + page->setIsPainting(true); +#endif + TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Paint", "data", InspectorPaintEvent::data(m_owningLayer.renderer(), clip, graphicsLayer)); + TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack()); + // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. + InspectorInstrumentation::willPaint(m_owningLayer.renderer(), graphicsLayer); + + if (graphicsLayer == m_graphicsLayer.get() + || graphicsLayer == m_foregroundLayer.get() + || graphicsLayer == m_backgroundLayer.get() + || graphicsLayer == m_maskLayer.get() + || graphicsLayer == m_childClippingMaskLayer.get() + || graphicsLayer == m_scrollingContentsLayer.get() + || graphicsLayer == m_scrollingBlockSelectionLayer.get()) { + + GraphicsLayerPaintInfo paintInfo; + paintInfo.renderLayer = &m_owningLayer; + paintInfo.compositedBounds = compositedBounds(); + paintInfo.offsetFromRenderer = graphicsLayer->offsetFromRenderer(); + paintInfo.paintingPhase = paintingPhase; + paintInfo.isBackgroundLayer = (graphicsLayer == m_backgroundLayer); + + // We have to use the same root as for hit testing, because both methods can compute and cache clipRects. + doPaintTask(paintInfo, &context, clip); + } else if (graphicsLayer == m_squashingLayer.get()) { + ASSERT(compositor()->layerSquashingEnabled()); + for (size_t i = 0; i < m_squashedLayers.size(); ++i) + doPaintTask(m_squashedLayers[i], &context, clip); + } else if (graphicsLayer == layerForHorizontalScrollbar()) { + paintScrollbar(m_owningLayer.scrollableArea()->horizontalScrollbar(), context, clip); + } else if (graphicsLayer == layerForVerticalScrollbar()) { + paintScrollbar(m_owningLayer.scrollableArea()->verticalScrollbar(), context, clip); + } else if (graphicsLayer == layerForScrollCorner()) { + const IntRect& scrollCornerAndResizer = m_owningLayer.scrollableArea()->scrollCornerAndResizerRect(); + context.save(); + context.translate(-scrollCornerAndResizer.x(), -scrollCornerAndResizer.y()); + IntRect transformedClip = clip; + transformedClip.moveBy(scrollCornerAndResizer.location()); + m_owningLayer.scrollableArea()->paintScrollCorner(&context, IntPoint(), transformedClip); + m_owningLayer.scrollableArea()->paintResizer(&context, IntPoint(), transformedClip); + context.restore(); + } + InspectorInstrumentation::didPaint(m_owningLayer.renderer(), graphicsLayer, &context, clip); +#ifndef NDEBUG + if (Page* page = renderer()->frame()->page()) + page->setIsPainting(false); +#endif +} + +bool CompositedLayerMapping::isTrackingRepaints() const +{ + GraphicsLayerClient* client = compositor(); + return client ? client->isTrackingRepaints() : false; +} + +struct CollectTrackedRepaintRectsFunctor { + void operator() (GraphicsLayer* layer) const { layer->collectTrackedRepaintRects(*rects); } + Vector<FloatRect>* rects; +}; + +PassOwnPtr<Vector<FloatRect> > CompositedLayerMapping::collectTrackedRepaintRects() const +{ + OwnPtr<Vector<FloatRect> > rects = adoptPtr(new Vector<FloatRect>); + CollectTrackedRepaintRectsFunctor functor = { rects.get() }; + ApplyToGraphicsLayers(this, functor, ApplyToAllGraphicsLayers); + return rects.release(); +} + +#ifndef NDEBUG +void CompositedLayerMapping::verifyNotPainting() +{ + ASSERT(!renderer()->frame()->page() || !renderer()->frame()->page()->isPainting()); +} +#endif + +void CompositedLayerMapping::notifyAnimationStarted(const GraphicsLayer*, double monotonicTime) +{ + renderer()->node()->document().compositorPendingAnimations().notifyCompositorAnimationStarted(monotonicTime); +} + +IntRect CompositedLayerMapping::pixelSnappedCompositedBounds() const +{ + LayoutRect bounds = m_compositedBounds; + bounds.move(m_owningLayer.subpixelAccumulation()); + return pixelSnappedIntRect(bounds); +} + +bool CompositedLayerMapping::updateSquashingLayerAssignment(RenderLayer* squashedLayer, const RenderLayer& owningLayer, size_t nextSquashedLayerIndex) +{ + ASSERT(compositor()->layerSquashingEnabled()); + + GraphicsLayerPaintInfo paintInfo; + paintInfo.renderLayer = squashedLayer; + // NOTE: composited bounds are updated elsewhere + // NOTE: offsetFromRenderer is updated elsewhere + paintInfo.paintingPhase = GraphicsLayerPaintAllWithOverflowClip; + paintInfo.isBackgroundLayer = false; + + // Change tracking on squashing layers: at the first sign of something changed, just invalidate the layer. + // FIXME: Perhaps we can find a tighter more clever mechanism later. + bool updatedAssignment = false; + if (nextSquashedLayerIndex < m_squashedLayers.size()) { + if (!paintInfo.isEquivalentForSquashing(m_squashedLayers[nextSquashedLayerIndex])) { + compositor()->repaintOnCompositingChange(squashedLayer); + updatedAssignment = true; + m_squashedLayers[nextSquashedLayerIndex] = paintInfo; + } + } else { + compositor()->repaintOnCompositingChange(squashedLayer); + m_squashedLayers.append(paintInfo); + updatedAssignment = true; + } + squashedLayer->setGroupedMapping(this); + return updatedAssignment; +} + +void CompositedLayerMapping::removeRenderLayerFromSquashingGraphicsLayer(const RenderLayer* layer) +{ + size_t layerIndex = kNotFound; + + for (size_t i = 0; i < m_squashedLayers.size(); ++i) { + if (m_squashedLayers[i].renderLayer == layer) { + layerIndex = i; + break; + } + } + + if (layerIndex == kNotFound) + return; + + m_squashedLayers.remove(layerIndex); +} + +void CompositedLayerMapping::finishAccumulatingSquashingLayers(size_t nextSquashedLayerIndex) +{ + ASSERT(compositor()->layerSquashingEnabled()); + + // Any additional squashed RenderLayers in the array no longer exist, and removing invalidates the squashingLayer contents. + if (nextSquashedLayerIndex < m_squashedLayers.size()) + m_squashedLayers.remove(nextSquashedLayerIndex, m_squashedLayers.size() - nextSquashedLayerIndex); +} + +String CompositedLayerMapping::debugName(const GraphicsLayer* graphicsLayer) +{ + String name; + if (graphicsLayer == m_graphicsLayer.get()) { + name = m_owningLayer.debugName(); + } else if (graphicsLayer == m_squashingContainmentLayer.get()) { + name = "Squashing Containment Layer"; + } else if (graphicsLayer == m_squashingLayer.get()) { + name = "Squashing Layer"; + } else if (graphicsLayer == m_ancestorClippingLayer.get()) { + name = "Ancestor Clipping Layer"; + } else if (graphicsLayer == m_foregroundLayer.get()) { + name = m_owningLayer.debugName() + " (foreground) Layer"; + } else if (graphicsLayer == m_backgroundLayer.get()) { + name = m_owningLayer.debugName() + " (background) Layer"; + } else if (graphicsLayer == m_childContainmentLayer.get()) { + name = "Child Containment Layer"; + } else if (graphicsLayer == m_childTransformLayer.get()) { + name = "Child Transform Layer"; + } else if (graphicsLayer == m_maskLayer.get()) { + name = "Mask Layer"; + } else if (graphicsLayer == m_childClippingMaskLayer.get()) { + name = "Child Clipping Mask Layer"; + } else if (graphicsLayer == m_layerForHorizontalScrollbar.get()) { + name = "Horizontal Scrollbar Layer"; + } else if (graphicsLayer == m_layerForVerticalScrollbar.get()) { + name = "Vertical Scrollbar Layer"; + } else if (graphicsLayer == m_layerForScrollCorner.get()) { + name = "Scroll Corner Layer"; + } else if (graphicsLayer == m_scrollingLayer.get()) { + name = "Scrolling Layer"; + } else if (graphicsLayer == m_scrollingContentsLayer.get()) { + name = "Scrolling Contents Layer"; + } else if (graphicsLayer == m_scrollingBlockSelectionLayer.get()) { + name = "Scrolling Block Selection Layer"; + } else { + ASSERT_NOT_REACHED(); + } + + return name; +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/CompositedLayerMapping.h b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMapping.h index b0f85e44d0e..22a0d75a125 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/CompositedLayerMapping.h +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMapping.h @@ -27,40 +27,51 @@ #define CompositedLayerMapping_h #include "core/rendering/RenderLayer.h" +#include "core/rendering/compositing/GraphicsLayerUpdater.h" #include "platform/geometry/FloatPoint.h" #include "platform/geometry/FloatPoint3D.h" #include "platform/graphics/GraphicsLayer.h" #include "platform/graphics/GraphicsLayerClient.h" -#include "platform/transforms/TransformationMatrix.h" namespace WebCore { -class KeyframeList; class RenderLayerCompositor; -class WebAnimationProvider; - -enum CompositingLayerType { - NormalCompositingLayer, // non-tiled layer with backing store - MediaCompositingLayer, // layer that contains an image, video, webGL or plugin - ContainerCompositingLayer // layer with no backing store -}; - // A GraphicsLayerPaintInfo contains all the info needed to paint a partial subtree of RenderLayers into a GraphicsLayer. struct GraphicsLayerPaintInfo { RenderLayer* renderLayer; - IntRect compositedBounds; + LayoutRect compositedBounds; - // A temporary offset used for squashing layers, when the origin of the - // squashing layer is not yet known. - IntSize offsetFromBackingRoot; + // The clip rect to apply, in the local coordinate space of the squashed layer, when painting it. + IntRect localClipRectForSquashedLayer; + // Offset describing where this squashed RenderLayer paints into the shared GraphicsLayer backing. IntSize offsetFromRenderer; + bool offsetFromRendererSet; + + LayoutSize subpixelAccumulation; GraphicsLayerPaintingPhase paintingPhase; bool isBackgroundLayer; + + GraphicsLayerPaintInfo() : renderLayer(0), offsetFromRendererSet(false), isBackgroundLayer(false) { } + + bool isEquivalentForSquashing(const GraphicsLayerPaintInfo& other) + { + // FIXME: offsetFromRenderer and compositedBounds should not be checked here, because + // they are not yet fixed at the time this function is used. + return renderLayer == other.renderLayer + && paintingPhase == other.paintingPhase + && isBackgroundLayer == other.isBackgroundLayer; + } +}; + +enum GraphicsLayerUpdateScope { + GraphicsLayerUpdateNone, + GraphicsLayerUpdateLocal, + GraphicsLayerUpdateSubtree, }; // CompositedLayerMapping keeps track of how RenderLayers of the render tree correspond to @@ -70,26 +81,20 @@ struct GraphicsLayerPaintInfo { // // Currently (Oct. 2013) there is one CompositedLayerMapping for each RenderLayer, // but this is likely to evolve soon. -class CompositedLayerMapping : public GraphicsLayerClient { +class CompositedLayerMapping FINAL : public GraphicsLayerClient { WTF_MAKE_NONCOPYABLE(CompositedLayerMapping); WTF_MAKE_FAST_ALLOCATED; public: - explicit CompositedLayerMapping(RenderLayer*); - ~CompositedLayerMapping(); - - RenderLayer* owningLayer() const { return m_owningLayer; } + explicit CompositedLayerMapping(RenderLayer&); + virtual ~CompositedLayerMapping(); - enum UpdateAfterLayoutFlag { - CompositingChildrenOnly = 1 << 0, - NeedsFullRepaint = 1 << 1, - IsUpdateRoot = 1 << 2 - }; - typedef unsigned UpdateAfterLayoutFlags; - void updateAfterLayout(UpdateAfterLayoutFlags); + RenderLayer& owningLayer() const { return m_owningLayer; } // Returns true if layer configuration changed. - bool updateGraphicsLayerConfiguration(); + bool updateGraphicsLayerConfiguration(GraphicsLayerUpdater::UpdateType); // Update graphics layer position and bounds. - void updateGraphicsLayerGeometry(); // make private + + void updateGraphicsLayerGeometry(GraphicsLayerUpdater::UpdateType, const RenderLayer* compositingContainer, Vector<RenderLayer*>& layersNeedingPaintInvalidation); + // Update whether layer needs blending. void updateContentsOpaque(); @@ -112,14 +117,25 @@ public: bool hasScrollingLayer() const { return m_scrollingLayer; } GraphicsLayer* scrollingLayer() const { return m_scrollingLayer.get(); } GraphicsLayer* scrollingContentsLayer() const { return m_scrollingContentsLayer.get(); } + GraphicsLayer* scrollingBlockSelectionLayer() const { return m_scrollingBlockSelectionLayer.get(); } bool hasMaskLayer() const { return m_maskLayer; } + GraphicsLayer* maskLayer() const { return m_maskLayer.get(); } + bool hasChildClippingMaskLayer() const { return m_childClippingMaskLayer; } + GraphicsLayer* childClippingMaskLayer() const { return m_childClippingMaskLayer.get(); } GraphicsLayer* parentForSublayers() const; GraphicsLayer* childForSuperlayers() const; + // localRootForOwningLayer does not include the m_squashingContainmentLayer, which is technically not associated with this CLM's owning layer. + GraphicsLayer* localRootForOwningLayer() const; + + GraphicsLayer* childTransformLayer() const { return m_childTransformLayer.get(); } + GraphicsLayer* squashingContainmentLayer() const { return m_squashingContainmentLayer.get(); } GraphicsLayer* squashingLayer() const { return m_squashingLayer.get(); } + // Contains the bottommost layer in the hierarchy that can contain the children transform. + GraphicsLayer* layerForChildrenTransform() const; // Returns true for a composited layer that has no backing store of its own, so // paints into some ancestor layer. @@ -134,6 +150,7 @@ public: // a backing store changed. bool updateRequiresOwnBackingStoreForIntrinsicReasons(); + void setSquashingContentsNeedDisplay(); void setContentsNeedDisplay(); // r is in the coordinate space of the layer's render object void setContentsNeedDisplayInRect(const IntRect&); @@ -141,47 +158,33 @@ public: // Notification from the renderer that its content changed. void contentChanged(ContentChangeType); - // Interface to start, finish, suspend and resume animations and transitions - bool startTransition(double, CSSPropertyID, const RenderStyle* fromStyle, const RenderStyle* toStyle); - void transitionPaused(double timeOffset, CSSPropertyID); - void transitionFinished(CSSPropertyID); - - bool startAnimation(double timeOffset, const CSSAnimationData*, const KeyframeList& keyframes); - void animationPaused(double timeOffset, const String& name); - void animationFinished(const String& name); + LayoutRect compositedBounds() const { return m_compositedBounds; } + IntRect pixelSnappedCompositedBounds() const; + void updateCompositedBounds(GraphicsLayerUpdater::UpdateType); - IntRect compositedBounds() const; - void setCompositedBounds(const IntRect&); - void updateCompositedBounds(); - - void updateAfterWidgetResize(); void positionOverflowControlsLayers(const IntSize& offsetFromRoot); bool hasUnpositionedOverflowControlsLayers() const; - void addRenderLayerToSquashingGraphicsLayer(RenderLayer*, IntSize offsetFromTargetBacking, size_t nextSquashedLayerIndex); + // Returns true if the assignment actually changed the assigned squashing layer. + bool updateSquashingLayerAssignment(RenderLayer* squashedLayer, const RenderLayer& owningLayer, size_t nextSquashedLayerIndex); + void removeRenderLayerFromSquashingGraphicsLayer(const RenderLayer*); + void finishAccumulatingSquashingLayers(size_t nextSquashedLayerIndex); + void updateRenderingContext(); + void updateShouldFlattenTransform(); // GraphicsLayerClient interface - virtual void notifyAnimationStarted(const GraphicsLayer*, double wallClockTime, double monotonicTime) OVERRIDE; - + virtual void notifyAnimationStarted(const GraphicsLayer*, double monotonicTime) OVERRIDE; virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& clip) OVERRIDE; - - virtual void didCommitChangesForLayer(const GraphicsLayer*) const OVERRIDE; - virtual bool getCurrentTransform(const GraphicsLayer*, TransformationMatrix&) const OVERRIDE; - virtual bool isTrackingRepaints() const OVERRIDE; PassOwnPtr<Vector<FloatRect> > collectTrackedRepaintRects() const; #ifndef NDEBUG - virtual void verifyNotPainting(); + virtual void verifyNotPainting() OVERRIDE; #endif - IntRect contentsBox() const; - IntRect backgroundBox() const; - - // For informative purposes only. - CompositingLayerType compositingLayerType() const; + LayoutRect contentsBox() const; GraphicsLayer* layerForHorizontalScrollbar() const { return m_layerForHorizontalScrollbar.get(); } GraphicsLayer* layerForVerticalScrollbar() const { return m_layerForVerticalScrollbar.get(); } @@ -190,48 +193,88 @@ public: void updateFilters(const RenderStyle*); bool canCompositeFilters() const { return m_canCompositeFilters; } - // Return an estimate of the backing store area (in pixels) allocated by this object's GraphicsLayers. - double backingStoreMemoryEstimate() const; - void setBlendMode(blink::WebBlendMode); + void setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateScope scope) { m_pendingUpdateScope = std::max(static_cast<GraphicsLayerUpdateScope>(m_pendingUpdateScope), scope); } + void clearNeedsGraphicsLayerUpdate() { m_pendingUpdateScope = GraphicsLayerUpdateNone; } + + bool shouldUpdateGraphicsLayer(GraphicsLayerUpdater::UpdateType updateType) const { return m_pendingUpdateScope > GraphicsLayerUpdateNone || updateType == GraphicsLayerUpdater::ForceUpdate; } + GraphicsLayerUpdater::UpdateType updateTypeForChildren(GraphicsLayerUpdater::UpdateType) const; + +#if ASSERT_ENABLED + void assertNeedsToUpdateGraphicsLayerBitsCleared() { ASSERT(m_pendingUpdateScope == GraphicsLayerUpdateNone); } +#endif + virtual String debugName(const GraphicsLayer*) OVERRIDE; + LayoutSize contentOffsetInCompositingLayer() const; + + LayoutPoint squashingOffsetFromTransformedAncestor() + { + return m_squashingLayerOffsetFromTransformedAncestor; + } + + // If there is a squashed layer painting into this CLM that is an ancestor of the given RenderObject, return it. Otherwise return 0. + const GraphicsLayerPaintInfo* containingSquashedLayer(const RenderObject*); + + void updateScrollingBlockSelection(); + private: + static const GraphicsLayerPaintInfo* containingSquashedLayer(const RenderObject*, const Vector<GraphicsLayerPaintInfo>& layers); + + // Helper methods to updateGraphicsLayerGeometry: + void computeGraphicsLayerParentLocation(const RenderLayer* compositingContainer, const IntRect& ancestorCompositingBounds, IntPoint& graphicsLayerParentLocation); + void updateSquashingLayerGeometry(const LayoutPoint& offsetFromCompositedAncestor, const IntPoint& graphicsLayerParentLocation, const RenderLayer& referenceLayer, Vector<GraphicsLayerPaintInfo>& layers, GraphicsLayer*, LayoutPoint* offsetFromTransformedAncestor, Vector<RenderLayer*>& layersNeedingPaintInvalidation); + void updateMainGraphicsLayerGeometry(const IntRect& relativeCompositingBounds, const IntRect& localCompositingBounds, IntPoint& graphicsLayerParentLocation); + void updateAncestorClippingLayerGeometry(const RenderLayer* compositingContainer, const IntPoint& snappedOffsetFromCompositedAncestor, IntPoint& graphicsLayerParentLocation); + void updateChildContainmentLayerGeometry(const IntRect& clippingBox, const IntRect& localCompositingBounds); + void updateChildTransformLayerGeometry(); + void updateMaskLayerGeometry(); + void updateTransformGeometry(const IntPoint& snappedOffsetFromCompositedAncestor, const IntRect& relativeCompositingBounds); + void updateForegroundLayerGeometry(const FloatSize& relativeCompositingBoundsSize, const IntRect& clippingBox); + void updateBackgroundLayerGeometry(const FloatSize& relativeCompositingBoundsSize); + void updateReflectionLayerGeometry(Vector<RenderLayer*>& layersNeedingPaintInvalidation); + void updateScrollingLayerGeometry(const IntRect& localCompositingBounds); + void updateChildClippingMaskLayerGeometry(); + void createPrimaryGraphicsLayer(); void destroyGraphicsLayers(); PassOwnPtr<GraphicsLayer> createGraphicsLayer(CompositingReasons); + bool toggleScrollbarLayerIfNeeded(OwnPtr<GraphicsLayer>&, bool needsLayer, CompositingReasons); - RenderLayerModelObject* renderer() const { return m_owningLayer->renderer(); } - RenderLayerCompositor* compositor() const { return m_owningLayer->compositor(); } + RenderLayerModelObject* renderer() const { return m_owningLayer.renderer(); } + RenderLayerCompositor* compositor() const { return m_owningLayer.compositor(); } void updateInternalHierarchy(); + void updatePaintingPhases(); bool updateClippingLayers(bool needsAncestorClip, bool needsDescendantClip); + bool updateChildTransformLayer(bool needsChildTransformLayer); bool updateOverflowControlsLayers(bool needsHorizontalScrollbarLayer, bool needsVerticalScrollbarLayer, bool needsScrollCornerLayer); bool updateForegroundLayer(bool needsForegroundLayer); bool updateBackgroundLayer(bool needsBackgroundLayer); bool updateMaskLayer(bool needsMaskLayer); bool updateClippingMaskLayers(bool needsChildClippingMaskLayer); - bool requiresHorizontalScrollbarLayer() const { return m_owningLayer->scrollableArea() && m_owningLayer->scrollableArea()->horizontalScrollbar(); } - bool requiresVerticalScrollbarLayer() const { return m_owningLayer->scrollableArea() && m_owningLayer->scrollableArea()->verticalScrollbar(); } - bool requiresScrollCornerLayer() const { return m_owningLayer->scrollableArea() && !m_owningLayer->scrollableArea()->scrollCornerAndResizerRect().isEmpty(); } + bool requiresHorizontalScrollbarLayer() const { return m_owningLayer.scrollableArea() && m_owningLayer.scrollableArea()->horizontalScrollbar(); } + bool requiresVerticalScrollbarLayer() const { return m_owningLayer.scrollableArea() && m_owningLayer.scrollableArea()->verticalScrollbar(); } + bool requiresScrollCornerLayer() const { return m_owningLayer.scrollableArea() && !m_owningLayer.scrollableArea()->scrollCornerAndResizerRect().isEmpty(); } bool updateScrollingLayers(bool scrollingLayers); void updateScrollParent(RenderLayer*); void updateClipParent(RenderLayer*); bool updateSquashingLayers(bool needsSquashingLayers); - void updateDrawsContent(bool isSimpleContainer); + void updateDrawsContent(); + void updateChildrenTransform(); void registerScrollingLayers(); + // Also sets subpixelAccumulation on the layer. + void computeBoundsOfOwningLayer(const RenderLayer* compositedAncestor, IntRect& localCompositingBounds, IntRect& compositingBoundsRelativeToCompositedAncestor, LayoutPoint& offsetFromCompositedAncestor, IntPoint& snappedOffsetFromCompositedAncestor); + void setBackgroundLayerPaintsFixedRootBackground(bool); GraphicsLayerPaintingPhase paintingPhaseForPrimaryLayer() const; - IntSize contentOffsetInCompostingLayer() const; // Result is transform origin in pixels. FloatPoint3D computeTransformOrigin(const IntRect& borderBox) const; - // Result is perspective origin in pixels. - FloatPoint computePerspectiveOrigin(const IntRect& borderBox) const; void updateOpacity(const RenderStyle*); void updateTransform(const RenderStyle*); @@ -242,39 +285,42 @@ 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. - bool containsPaintedContent(bool isSimpleContainer) const; + bool containsPaintedContent() const; // Returns true if the RenderLayer just contains an image that we can composite directly. bool isDirectlyCompositedImage() const; void updateImageContents(); Color rendererBackgroundColor() const; - void updateBackgroundColor(bool isSimpleContainer); - void updateContentsRect(bool isSimpleContainer); - + void updateBackgroundColor(); + void updateContentsRect(); + void updateAfterWidgetResize(); void updateCompositingReasons(); - bool hasVisibleNonCompositingDescendantLayers() const; - - bool shouldClipCompositedBounds() const; + static bool hasVisibleNonCompositingDescendant(RenderLayer* parent); void paintsIntoCompositedAncestorChanged(); void doPaintTask(GraphicsLayerPaintInfo&, GraphicsContext*, const IntRect& clip); - RenderLayer* m_owningLayer; + // Computes the background clip rect for the given squashed layer, up to any containing layer that is squashed into the + // same squashing layer and contains this squashed layer's clipping ancestor. + // The clip rect is returned in the coordinate space of the given squashed layer. + // If there is no such containing layer, returns the infinite rect. + // FIXME: unify this code with the code that sets up m_ancestorClippingLayer. They are doing very similar things. + static IntRect localClipRectForSquashedLayer(const RenderLayer& referenceLayer, const GraphicsLayerPaintInfo&, const Vector<GraphicsLayerPaintInfo>& layers); + + RenderLayer& m_owningLayer; // The hierarchy of layers that is maintained by the CompositedLayerMapping looks like this: // // + m_ancestorClippingLayer [OPTIONAL] // + m_graphicsLayer - // + m_childContainmentLayer [OPTIONAL] <-OR-> m_scrollingLayer [OPTIONAL] - // + m_scrollingContentsLayer [OPTIONAL] + // + m_childContainmentLayer [OPTIONAL] <-OR-> m_scrollingLayer [OPTIONAL] <-OR-> m_childTransformLayer + // + m_scrollingContentsLayer [Present iff m_scrollingLayer is present] + // + m_scrollingBlockSelectionLayer [Present iff m_scrollingLayer is present] // // We need an ancestor clipping layer if our clipping ancestor is not our ancestor in the // clipping tree. Here's what that might look like. @@ -299,8 +345,10 @@ private: OwnPtr<GraphicsLayer> m_ancestorClippingLayer; // Only used if we are clipped by an ancestor which is not a stacking context. OwnPtr<GraphicsLayer> m_graphicsLayer; OwnPtr<GraphicsLayer> m_childContainmentLayer; // Only used if we have clipping on a stacking context with compositing children. + OwnPtr<GraphicsLayer> m_childTransformLayer; // Only used if we have perspective and no m_childContainmentLayer. OwnPtr<GraphicsLayer> m_scrollingLayer; // Only used if the layer is using composited scrolling. OwnPtr<GraphicsLayer> m_scrollingContentsLayer; // Only used if the layer is using composited scrolling. + OwnPtr<GraphicsLayer> m_scrollingBlockSelectionLayer; // Only used if the layer is using composited scrolling, but has no scrolling contents apart from block selection gaps. // This layer is also added to the hierarchy by the RLB, but in a different way than // the layers above. It's added to m_graphicsLayer as its mask layer (naturally) if @@ -337,21 +385,33 @@ private: OwnPtr<GraphicsLayer> m_layerForVerticalScrollbar; OwnPtr<GraphicsLayer> m_layerForScrollCorner; - OwnPtr<WebAnimationProvider> m_animationProvider; - - OwnPtr<GraphicsLayer> m_squashingContainmentLayer; // Only used if any squashed layers exist, to contain the squashed layers as siblings to the rest of the GraphicsLayer tree chunk. + // A squashing CLM has two possible squashing-related structures. + // + // If m_ancestorClippingLayer is present: + // + // m_ancestorClippingLayer + // + m_graphicsLayer + // + m_squashingLayer + // + // If not: + // + // m_squashingContainmentLayer + // + m_graphicsLayer + // + m_squashingLayer + OwnPtr<GraphicsLayer> m_squashingContainmentLayer; // Only used if any squashed layers exist and m_squashingContainmentLayer is not present, to contain the squashed layers as siblings to the rest of the GraphicsLayer tree chunk. OwnPtr<GraphicsLayer> m_squashingLayer; // Only used if any squashed layers exist, this is the backing that squashed layers paint into. Vector<GraphicsLayerPaintInfo> m_squashedLayers; + LayoutPoint m_squashingLayerOffsetFromTransformedAncestor; - IntRect m_compositedBounds; + LayoutRect m_compositedBounds; - bool m_artificiallyInflatedBounds; // bounds had to be made non-zero to make transform-origin work - bool m_boundsConstrainedByClipping; - bool m_isMainFrameRenderViewLayer; - bool m_requiresOwnBackingStoreForIntrinsicReasons; - bool m_requiresOwnBackingStoreForAncestorReasons; - bool m_canCompositeFilters; - bool m_backgroundLayerPaintsFixedRootBackground; + unsigned m_pendingUpdateScope : 2; + unsigned m_isMainFrameRenderViewLayer : 1; + unsigned m_requiresOwnBackingStoreForIntrinsicReasons : 1; + unsigned m_requiresOwnBackingStoreForAncestorReasons : 1; + unsigned m_canCompositeFilters : 1; + unsigned m_backgroundLayerPaintsFixedRootBackground : 1; + unsigned m_scrollingContentsAreEmpty : 1; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/CompositedLayerMappingPtr.h b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMappingPtr.h index 27cb68581d5..27cb68581d5 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/CompositedLayerMappingPtr.h +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMappingPtr.h diff --git a/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingInputsUpdater.cpp b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingInputsUpdater.cpp new file mode 100644 index 00000000000..af8ea1f0973 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingInputsUpdater.cpp @@ -0,0 +1,94 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" +#include "core/rendering/compositing/CompositingInputsUpdater.h" + +#include "core/rendering/RenderBlock.h" +#include "core/rendering/RenderLayer.h" +#include "core/rendering/compositing/CompositedLayerMapping.h" + +namespace WebCore { + +CompositingInputsUpdater::CompositingInputsUpdater(RenderLayer* rootRenderLayer) + : m_geometryMap(UseTransforms) + , m_rootRenderLayer(rootRenderLayer) +{ + rootRenderLayer->updateDescendantDependentFlags(); +} + +CompositingInputsUpdater::~CompositingInputsUpdater() +{ +} + +void CompositingInputsUpdater::update(RenderLayer* layer, UpdateType updateType, AncestorInfo info) +{ + if (!layer->childNeedsCompositingInputsUpdate() && updateType != ForceUpdate) + return; + + m_geometryMap.pushMappingsToAncestor(layer, layer->parent()); + + if (layer->hasCompositedLayerMapping()) + info.enclosingCompositedLayer = layer; + + if (layer->needsCompositingInputsUpdate()) { + if (info.enclosingCompositedLayer) + info.enclosingCompositedLayer->compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree); + updateType = ForceUpdate; + } + + if (updateType == ForceUpdate) { + RenderLayer::CompositingInputs properties; + + if (!layer->isRootLayer()) { + properties.clippedAbsoluteBoundingBox = enclosingIntRect(m_geometryMap.absoluteRect(layer->boundingBoxForCompositingOverlapTest())); + // FIXME: Setting the absBounds to 1x1 instead of 0x0 makes very little sense, + // but removing this code will make JSGameBench sad. + // See https://codereview.chromium.org/13912020/ + if (properties.clippedAbsoluteBoundingBox.isEmpty()) + properties.clippedAbsoluteBoundingBox.setSize(IntSize(1, 1)); + + IntRect clipRect = pixelSnappedIntRect(layer->clipper().backgroundClipRect(ClipRectsContext(m_rootRenderLayer, AbsoluteClipRects)).rect()); + properties.clippedAbsoluteBoundingBox.intersect(clipRect); + + const RenderLayer* parent = layer->parent(); + properties.opacityAncestor = parent->isTransparent() ? parent : parent->compositingInputs().opacityAncestor; + properties.transformAncestor = parent->transform() ? parent : parent->compositingInputs().transformAncestor; + properties.filterAncestor = parent->hasFilter() ? parent : parent->compositingInputs().filterAncestor; + + if (layer->renderer()->isOutOfFlowPositioned() && info.ancestorScrollingLayer && !layer->subtreeIsInvisible()) { + const RenderObject* container = layer->renderer()->containingBlock(); + const RenderObject* scroller = info.ancestorScrollingLayer->renderer(); + properties.isUnclippedDescendant = scroller != container && scroller->isDescendantOf(container); + } + } + + layer->updateCompositingInputs(properties); + } + + if (layer->scrollsOverflow()) + info.ancestorScrollingLayer = layer; + + for (RenderLayer* child = layer->firstChild(); child; child = child->nextSibling()) + update(child, updateType, info); + + m_geometryMap.popMappingsToAncestor(layer->parent()); + + layer->clearChildNeedsCompositingInputsUpdate(); +} + +#if ASSERT_ENABLED + +void CompositingInputsUpdater::assertNeedsCompositingInputsUpdateBitsCleared(RenderLayer* layer) +{ + ASSERT(!layer->childNeedsCompositingInputsUpdate()); + ASSERT(!layer->needsCompositingInputsUpdate()); + + for (RenderLayer* child = layer->firstChild(); child; child = child->nextSibling()) + assertNeedsCompositingInputsUpdateBitsCleared(child); +} + +#endif + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingInputsUpdater.h b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingInputsUpdater.h new file mode 100644 index 00000000000..49086287061 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingInputsUpdater.h @@ -0,0 +1,49 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CompositingInputsUpdater_h +#define CompositingInputsUpdater_h + +#include "core/rendering/RenderGeometryMap.h" + +namespace WebCore { + +class RenderLayer; + +class CompositingInputsUpdater { +private: + struct AncestorInfo { + AncestorInfo() + : enclosingCompositedLayer(0) + , ancestorScrollingLayer(0) + { + } + + RenderLayer* enclosingCompositedLayer; + RenderLayer* ancestorScrollingLayer; + }; + +public: + explicit CompositingInputsUpdater(RenderLayer* rootRenderLayer); + ~CompositingInputsUpdater(); + + enum UpdateType { + DoNotForceUpdate, + ForceUpdate, + }; + + void update(RenderLayer*, UpdateType = DoNotForceUpdate, AncestorInfo = AncestorInfo()); + +#if ASSERT_ENABLED + static void assertNeedsCompositingInputsUpdateBitsCleared(RenderLayer*); +#endif + +private: + RenderGeometryMap m_geometryMap; + RenderLayer* m_rootRenderLayer; +}; + +} // namespace WebCore + +#endif // CompositingInputsUpdater_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingLayerAssigner.cpp b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingLayerAssigner.cpp new file mode 100644 index 00000000000..e3d944fef94 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingLayerAssigner.cpp @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2014 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 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 "core/rendering/compositing/CompositingLayerAssigner.h" + +#include "core/rendering/compositing/CompositedLayerMapping.h" + +namespace WebCore { + +// We will only allow squashing if the bbox-area:squashed-area doesn't exceed +// the ratio |gSquashingSparsityTolerance|:1. +static uint64_t gSquashingSparsityTolerance = 6; + +CompositingLayerAssigner::CompositingLayerAssigner(RenderLayerCompositor* compositor) + : m_compositor(compositor) + , m_layerSquashingEnabled(compositor->layerSquashingEnabled()) +{ +} + +CompositingLayerAssigner::~CompositingLayerAssigner() +{ +} + +void CompositingLayerAssigner::assign(RenderLayer* updateRoot, bool& layersChanged, Vector<RenderLayer*>& layersNeedingRepaint) +{ + SquashingState squashingState; + assignLayersToBackingsInternal(updateRoot, squashingState, layersChanged, layersNeedingRepaint); + if (squashingState.hasMostRecentMapping) + squashingState.mostRecentMapping->finishAccumulatingSquashingLayers(squashingState.nextSquashedLayerIndex); +} + +void CompositingLayerAssigner::SquashingState::updateSquashingStateForNewMapping(CompositedLayerMappingPtr newCompositedLayerMapping, bool hasNewCompositedLayerMapping) +{ + // The most recent backing is done accumulating any more squashing layers. + if (hasMostRecentMapping) + mostRecentMapping->finishAccumulatingSquashingLayers(nextSquashedLayerIndex); + + nextSquashedLayerIndex = 0; + boundingRect = IntRect(); + mostRecentMapping = newCompositedLayerMapping; + hasMostRecentMapping = hasNewCompositedLayerMapping; + haveAssignedBackingsToEntireSquashingLayerSubtree = false; +} + +bool CompositingLayerAssigner::squashingWouldExceedSparsityTolerance(const RenderLayer* candidate, const CompositingLayerAssigner::SquashingState& squashingState) +{ + IntRect bounds = candidate->compositingInputs().clippedAbsoluteBoundingBox; + IntRect newBoundingRect = squashingState.boundingRect; + newBoundingRect.unite(bounds); + const uint64_t newBoundingRectArea = newBoundingRect.size().area(); + const uint64_t newSquashedArea = squashingState.totalAreaOfSquashedRects + bounds.size().area(); + return newBoundingRectArea > gSquashingSparsityTolerance * newSquashedArea; +} + +bool CompositingLayerAssigner::needsOwnBacking(const RenderLayer* layer) const +{ + if (!m_compositor->canBeComposited(layer)) + return false; + + // If squashing is disabled, then layers that would have been squashed should just be separately composited. + bool needsOwnBackingForDisabledSquashing = !m_layerSquashingEnabled && requiresSquashing(layer->compositingReasons()); + + return requiresCompositing(layer->compositingReasons()) || needsOwnBackingForDisabledSquashing || (m_compositor->staleInCompositingMode() && layer->isRootLayer()); +} + +CompositingStateTransitionType CompositingLayerAssigner::computeCompositedLayerUpdate(RenderLayer* layer) +{ + CompositingStateTransitionType update = NoCompositingStateChange; + if (needsOwnBacking(layer)) { + if (!layer->hasCompositedLayerMapping()) { + update = AllocateOwnCompositedLayerMapping; + } + } else { + if (layer->hasCompositedLayerMapping()) + update = RemoveOwnCompositedLayerMapping; + + if (m_layerSquashingEnabled) { + if (!layer->subtreeIsInvisible() && requiresSquashing(layer->compositingReasons())) { + // We can't compute at this time whether the squashing layer update is a no-op, + // since that requires walking the render layer tree. + update = PutInSquashingLayer; + } else if (layer->groupedMapping() || layer->lostGroupedMapping()) { + update = RemoveFromSquashingLayer; + } + } + } + return update; +} + +CompositingReasons CompositingLayerAssigner::getReasonsPreventingSquashing(const RenderLayer* layer, const CompositingLayerAssigner::SquashingState& squashingState) +{ + if (!squashingState.haveAssignedBackingsToEntireSquashingLayerSubtree) + return CompositingReasonSquashingWouldBreakPaintOrder; + + // FIXME: this special case for video exists only to deal with corner cases + // where a RenderVideo does not report that it needs to be directly composited. + // Video does not currently support sharing a backing, but this could be + // generalized in the future. The following layout tests fail if we permit the + // video to share a backing with other layers. + // + // compositing/video/video-controls-layer-creation.html + // virtual/softwarecompositing/video/video-controls-layer-creation.html + if (layer->renderer()->isVideo()) + return CompositingReasonSquashingVideoIsDisallowed; + + if (squashingWouldExceedSparsityTolerance(layer, squashingState)) + return CompositingReasonSquashingSparsityExceeded; + + // FIXME: this is not efficient, since it walks up the tree . We should store these values on the CompositingInputsCache. + ASSERT(squashingState.hasMostRecentMapping); + const RenderLayer& squashingLayer = squashingState.mostRecentMapping->owningLayer(); + + if (layer->renderer()->clippingContainer() != squashingLayer.renderer()->clippingContainer()) { + if (!squashingLayer.compositedLayerMapping()->containingSquashedLayer(layer->renderer()->clippingContainer())) + return CompositingReasonSquashingClippingContainerMismatch; + } + + // Composited descendants need to be clipped by a child containment graphics layer, which would not be available if the layer is + // squashed (and therefore has no CLM nor a child containment graphics layer). + if (m_compositor->clipsCompositingDescendants(layer)) + return CompositingReasonSquashedLayerClipsCompositingDescendants; + + if (layer->scrollsWithRespectTo(&squashingLayer)) + return CompositingReasonScrollsWithRespectToSquashingLayer; + + const RenderLayer::CompositingInputs& compositingInputs = layer->compositingInputs(); + const RenderLayer::CompositingInputs& squashingLayerCompositingInputs = squashingLayer.compositingInputs(); + + if (compositingInputs.opacityAncestor != squashingLayerCompositingInputs.opacityAncestor) + return CompositingReasonSquashingOpacityAncestorMismatch; + + if (compositingInputs.transformAncestor != squashingLayerCompositingInputs.transformAncestor) + return CompositingReasonSquashingTransformAncestorMismatch; + + if (compositingInputs.filterAncestor != squashingLayerCompositingInputs.filterAncestor) + return CompositingReasonSquashingFilterAncestorMismatch; + + return CompositingReasonNone; +} + +bool CompositingLayerAssigner::updateSquashingAssignment(RenderLayer* layer, SquashingState& squashingState, const CompositingStateTransitionType compositedLayerUpdate, + Vector<RenderLayer*>& layersNeedingRepaint) +{ + // NOTE: In the future as we generalize this, the background of this layer may need to be assigned to a different backing than + // the squashed RenderLayer's own primary contents. This would happen when we have a composited negative z-index element that needs + // to paint on top of the background, but below the layer's main contents. For now, because we always composite layers + // when they have a composited negative z-index child, such layers will never need squashing so it is not yet an issue. + if (compositedLayerUpdate == PutInSquashingLayer) { + // A layer that is squashed with other layers cannot have its own CompositedLayerMapping. + ASSERT(!layer->hasCompositedLayerMapping()); + ASSERT(squashingState.hasMostRecentMapping); + + bool changedSquashingLayer = + squashingState.mostRecentMapping->updateSquashingLayerAssignment(layer, squashingState.mostRecentMapping->owningLayer(), squashingState.nextSquashedLayerIndex); + if (!changedSquashingLayer) + return true; + + // If we've modified the collection of squashed layers, we must update + // the graphics layer geometry. + squashingState.mostRecentMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree); + + layer->clipper().clearClipRectsIncludingDescendants(); + + // Issue a repaint, since |layer| may have been added to an already-existing squashing layer. + layersNeedingRepaint.append(layer); + + return true; + } + if (compositedLayerUpdate == RemoveFromSquashingLayer) { + if (layer->groupedMapping()) { + // Before removing |layer| from an already-existing squashing layer that may have other content, issue a repaint. + m_compositor->repaintOnCompositingChange(layer); + layer->groupedMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree); + layer->setGroupedMapping(0); + } + + // If we need to repaint, do so now that we've removed it from a squashed layer. + layersNeedingRepaint.append(layer); + + layer->setLostGroupedMapping(false); + return true; + } + + return false; +} + +void CompositingLayerAssigner::assignLayersToBackingsForReflectionLayer(RenderLayer* reflectionLayer, bool& layersChanged, Vector<RenderLayer*>& layersNeedingRepaint) +{ + CompositingStateTransitionType compositedLayerUpdate = computeCompositedLayerUpdate(reflectionLayer); + if (compositedLayerUpdate != NoCompositingStateChange) { + layersNeedingRepaint.append(reflectionLayer); + layersChanged = true; + m_compositor->allocateOrClearCompositedLayerMapping(reflectionLayer, compositedLayerUpdate); + } + m_compositor->updateDirectCompositingReasons(reflectionLayer); + if (reflectionLayer->hasCompositedLayerMapping()) + reflectionLayer->compositedLayerMapping()->updateGraphicsLayerConfiguration(GraphicsLayerUpdater::ForceUpdate); +} + +void CompositingLayerAssigner::assignLayersToBackingsInternal(RenderLayer* layer, SquashingState& squashingState, bool& layersChanged, Vector<RenderLayer*>& layersNeedingRepaint) +{ + if (m_layerSquashingEnabled && requiresSquashing(layer->compositingReasons())) { + CompositingReasons reasonsPreventingSquashing = getReasonsPreventingSquashing(layer, squashingState); + if (reasonsPreventingSquashing) + layer->setCompositingReasons(layer->compositingReasons() | reasonsPreventingSquashing); + } + + CompositingStateTransitionType compositedLayerUpdate = computeCompositedLayerUpdate(layer); + + if (m_compositor->allocateOrClearCompositedLayerMapping(layer, compositedLayerUpdate)) { + layersNeedingRepaint.append(layer); + layersChanged = true; + } + + // FIXME: special-casing reflection layers here is not right. + if (layer->reflectionInfo()) + assignLayersToBackingsForReflectionLayer(layer->reflectionInfo()->reflectionLayer(), layersChanged, layersNeedingRepaint); + + // Add this layer to a squashing backing if needed. + if (m_layerSquashingEnabled) { + if (updateSquashingAssignment(layer, squashingState, compositedLayerUpdate, layersNeedingRepaint)) + layersChanged = true; + + const bool layerIsSquashed = compositedLayerUpdate == PutInSquashingLayer || (compositedLayerUpdate == NoCompositingStateChange && layer->groupedMapping()); + if (layerIsSquashed) { + squashingState.nextSquashedLayerIndex++; + IntRect layerBounds = layer->compositingInputs().clippedAbsoluteBoundingBox; + squashingState.totalAreaOfSquashedRects += layerBounds.size().area(); + squashingState.boundingRect.unite(layerBounds); + } + } + + if (layer->stackingNode()->isStackingContext()) { + RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NegativeZOrderChildren); + while (RenderLayerStackingNode* curNode = iterator.next()) + assignLayersToBackingsInternal(curNode->layer(), squashingState, layersChanged, layersNeedingRepaint); + } + + if (m_layerSquashingEnabled) { + // At this point, if the layer is to be "separately" composited, then its backing becomes the most recent in paint-order. + if (layer->compositingState() == PaintsIntoOwnBacking || layer->compositingState() == HasOwnBackingButPaintsIntoAncestor) { + ASSERT(!requiresSquashing(layer->compositingReasons())); + squashingState.updateSquashingStateForNewMapping(layer->compositedLayerMapping(), layer->hasCompositedLayerMapping()); + } + } + + RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren); + while (RenderLayerStackingNode* curNode = iterator.next()) + assignLayersToBackingsInternal(curNode->layer(), squashingState, layersChanged, layersNeedingRepaint); + + if (squashingState.hasMostRecentMapping && &squashingState.mostRecentMapping->owningLayer() == layer) + squashingState.haveAssignedBackingsToEntireSquashingLayerSubtree = true; +} + +} diff --git a/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingLayerAssigner.h b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingLayerAssigner.h new file mode 100644 index 00000000000..ccc283d3e20 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingLayerAssigner.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2014 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 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 CompositingLayerAssigner_h +#define CompositingLayerAssigner_h + +#include "core/rendering/compositing/RenderLayerCompositor.h" +#include "platform/geometry/IntRect.h" +#include "platform/geometry/LayoutPoint.h" + +namespace WebCore { + +class RenderLayer; + +class CompositingLayerAssigner { +public: + explicit CompositingLayerAssigner(RenderLayerCompositor*); + ~CompositingLayerAssigner(); + + void assign(RenderLayer* updateRoot, bool& layersChanged, Vector<RenderLayer*>& layersNeedingRepaint); + + // FIXME: This function should be private. We should remove the one caller + // once we've fixed the compositing chicken/egg issues. + CompositingStateTransitionType computeCompositedLayerUpdate(RenderLayer*); + +private: + struct SquashingState { + SquashingState() + : mostRecentMapping(0) + , hasMostRecentMapping(false) + , haveAssignedBackingsToEntireSquashingLayerSubtree(false) + , nextSquashedLayerIndex(0) + , totalAreaOfSquashedRects(0) { } + + void updateSquashingStateForNewMapping(CompositedLayerMappingPtr, bool hasNewCompositedLayerMapping); + + // The most recent composited backing that the layer should squash onto if needed. + CompositedLayerMappingPtr mostRecentMapping; + bool hasMostRecentMapping; + + // Whether all RenderLayers in the stacking subtree rooted at the most recent mapping's + // owning layer have had CompositedLayerMappings assigned. Layers cannot squash into a + // CompositedLayerMapping owned by a stacking ancestor, since this changes paint order. + bool haveAssignedBackingsToEntireSquashingLayerSubtree; + + // Counter that tracks what index the next RenderLayer would be if it gets squashed to the current squashing layer. + size_t nextSquashedLayerIndex; + + // The absolute bounding rect of all the squashed layers. + IntRect boundingRect; + + // This is simply the sum of the areas of the squashed rects. This can be very skewed if the rects overlap, + // but should be close enough to drive a heuristic. + uint64_t totalAreaOfSquashedRects; + }; + + void assignLayersToBackingsInternal(RenderLayer*, SquashingState&, bool& layersChanged, Vector<RenderLayer*>& layersNeedingRepaint); + void assignLayersToBackingsForReflectionLayer(RenderLayer* reflectionLayer, bool& layersChanged, Vector<RenderLayer*>& layersNeedingRepaint); + CompositingReasons getReasonsPreventingSquashing(const RenderLayer*, const SquashingState&); + bool squashingWouldExceedSparsityTolerance(const RenderLayer* candidate, const SquashingState&); + bool updateSquashingAssignment(RenderLayer*, SquashingState&, CompositingStateTransitionType, Vector<RenderLayer*>& layersNeedingRepaint); + bool needsOwnBacking(const RenderLayer*) const; + + RenderLayerCompositor* m_compositor; + bool m_layerSquashingEnabled; +}; + +} // namespace WebCore + +#endif // CompositingLayerAssigner_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingReasonFinder.cpp b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingReasonFinder.cpp new file mode 100644 index 00000000000..289ba10aed5 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingReasonFinder.cpp @@ -0,0 +1,236 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" +#include "core/rendering/compositing/CompositingReasonFinder.h" + +#include "core/frame/FrameView.h" +#include "core/frame/Settings.h" +#include "core/page/Page.h" +#include "core/rendering/RenderView.h" +#include "core/rendering/compositing/RenderLayerCompositor.h" + +namespace WebCore { + +CompositingReasonFinder::CompositingReasonFinder(RenderView& renderView) + : m_renderView(renderView) + , m_compositingTriggers(static_cast<CompositingTriggerFlags>(AllCompositingTriggers)) +{ + updateTriggers(); +} + +void CompositingReasonFinder::updateTriggers() +{ + m_compositingTriggers = 0; + + Settings& settings = m_renderView.document().page()->settings(); + if (settings.acceleratedCompositingForVideoEnabled()) + m_compositingTriggers |= VideoTrigger; + if (settings.acceleratedCompositingForCanvasEnabled()) + m_compositingTriggers |= CanvasTrigger; + if (settings.compositedScrollingForFramesEnabled()) + m_compositingTriggers |= ScrollableInnerFrameTrigger; + if (settings.acceleratedCompositingForFiltersEnabled()) + m_compositingTriggers |= FilterTrigger; + + // We map both these settings to universal overlow scrolling. + // FIXME: Replace these settings with a generic compositing setting for HighDPI. + if (settings.acceleratedCompositingForOverflowScrollEnabled() || settings.compositorDrivenAcceleratedScrollingEnabled()) + m_compositingTriggers |= OverflowScrollTrigger; + + // FIXME: acceleratedCompositingForFixedPositionEnabled should be renamed acceleratedCompositingForViewportConstrainedPositionEnabled(). + // Or the sticky and fixed position elements should be behind different flags. + if (settings.acceleratedCompositingForFixedPositionEnabled()) + m_compositingTriggers |= ViewportConstrainedPositionedTrigger; +} + +bool CompositingReasonFinder::hasOverflowScrollTrigger() const +{ + return m_compositingTriggers & OverflowScrollTrigger; +} + +bool CompositingReasonFinder::isMainFrame() const +{ + // FIXME: LocalFrame::isMainFrame() is probably better. + return !m_renderView.document().ownerElement(); +} + +CompositingReasons CompositingReasonFinder::directReasons(const RenderLayer* layer) const +{ + CompositingReasons styleReasons = layer->styleDeterminedCompositingReasons(); + ASSERT(styleDeterminedReasons(layer->renderer()) == styleReasons); + return styleReasons | nonStyleDeterminedDirectReasons(layer); +} + +// This information doesn't appear to be incorporated into CompositingReasons. +bool CompositingReasonFinder::requiresCompositingForScrollableFrame() const +{ + // Need this done first to determine overflow. + ASSERT(!m_renderView.needsLayout()); + if (isMainFrame()) + return false; + + if (!(m_compositingTriggers & ScrollableInnerFrameTrigger)) + return false; + + return m_renderView.frameView()->isScrollable(); +} + +CompositingReasons CompositingReasonFinder::styleDeterminedReasons(RenderObject* renderer) const +{ + CompositingReasons directReasons = CompositingReasonNone; + + RenderStyle* style = renderer->style(); + + if (requiresCompositingForTransform(renderer)) + directReasons |= CompositingReason3DTransform; + + if (requiresCompositingForFilters(renderer)) + directReasons |= CompositingReasonFilters; + + if (style->backfaceVisibility() == BackfaceVisibilityHidden) + directReasons |= CompositingReasonBackfaceVisibilityHidden; + + if (requiresCompositingForAnimation(style)) + directReasons |= CompositingReasonActiveAnimation; + + if (style->hasWillChangeCompositingHint() && !style->subtreeWillChangeContents()) + directReasons |= CompositingReasonWillChangeCompositingHint; + + ASSERT(!(directReasons & ~CompositingReasonComboAllStyleDeterminedReasons)); + return directReasons; +} + +bool CompositingReasonFinder::requiresCompositingForTransform(RenderObject* renderer) const +{ + // Note that we ask the renderer if it has a transform, because the style may have transforms, + // but the renderer may be an inline that doesn't suppport them. + return renderer->hasTransform() && renderer->style()->transform().has3DOperation(); +} + +bool CompositingReasonFinder::requiresCompositingForFilters(RenderObject* renderer) const +{ + if (!(m_compositingTriggers & FilterTrigger)) + return false; + + return renderer->hasFilter(); +} + +CompositingReasons CompositingReasonFinder::nonStyleDeterminedDirectReasons(const RenderLayer* layer) const +{ + CompositingReasons directReasons = CompositingReasonNone; + RenderObject* renderer = layer->renderer(); + + if (hasOverflowScrollTrigger()) { + // IsUnclippedDescendant is only actually stale during the chicken/egg code path. + // FIXME: Use compositingInputs().isUnclippedDescendant to ASSERT that + // this value isn't stale. + if (layer->compositingInputs().isUnclippedDescendant) + directReasons |= CompositingReasonOutOfFlowClipping; + + if (layer->scrollParent()) + directReasons |= CompositingReasonOverflowScrollingParent; + + if (layer->needsCompositedScrolling()) + directReasons |= CompositingReasonOverflowScrollingTouch; + } + + if (requiresCompositingForPositionFixed(renderer, layer, 0)) + directReasons |= CompositingReasonPositionFixed; + + directReasons |= renderer->additionalCompositingReasons(m_compositingTriggers); + + ASSERT(!(directReasons & CompositingReasonComboAllStyleDeterminedReasons)); + return directReasons; +} + +bool CompositingReasonFinder::requiresCompositingForAnimation(RenderStyle* style) const +{ + if (style->subtreeWillChangeContents()) + return style->isRunningAnimationOnCompositor(); + + return style->shouldCompositeForCurrentAnimations(); +} + +bool CompositingReasonFinder::requiresCompositingForPositionFixed(RenderObject* renderer, const RenderLayer* layer, RenderLayer::ViewportConstrainedNotCompositedReason* viewportConstrainedNotCompositedReason) const +{ + if (!(m_compositingTriggers & ViewportConstrainedPositionedTrigger)) + return false; + + if (renderer->style()->position() != FixedPosition) + return false; + + RenderObject* container = renderer->container(); + // If the renderer is not hooked up yet then we have to wait until it is. + if (!container) { + ASSERT(m_renderView.document().lifecycle().state() < DocumentLifecycle::InCompositingUpdate); + // FIXME: Remove this and ASSERT(container) once we get rid of the incremental + // allocateOrClearCompositedLayerMapping compositing update. This happens when + // adding the renderer to the tree because we setStyle before addChild in + // createRendererForElementIfNeeded. + return false; + } + + // Don't promote fixed position elements that are descendants of a non-view container, e.g. transformed elements. + // They will stay fixed wrt the container rather than the enclosing frame. + if (container != &m_renderView) { + if (viewportConstrainedNotCompositedReason) + *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForNonViewContainer; + return false; + } + + // If the fixed-position element does not have any scrollable ancestor between it and + // its container, then we do not need to spend compositor resources for it. Start by + // assuming we can opt-out (i.e. no scrollable ancestor), and refine the answer below. + bool hasScrollableAncestor = false; + + // The FrameView has the scrollbars associated with the top level viewport, so we have to + // check the FrameView in addition to the hierarchy of ancestors. + FrameView* frameView = m_renderView.frameView(); + if (frameView && frameView->isScrollable()) + hasScrollableAncestor = true; + + RenderLayer* ancestor = layer->parent(); + while (ancestor && !hasScrollableAncestor) { + if (ancestor->scrollsOverflow()) + hasScrollableAncestor = true; + if (ancestor->renderer() == &m_renderView) + break; + ancestor = ancestor->parent(); + } + + if (!hasScrollableAncestor) { + if (viewportConstrainedNotCompositedReason) + *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForUnscrollableAncestors; + return false; + } + + // Subsequent tests depend on layout. If we can't tell now, just keep things the way they are until layout is done. + // FIXME: Get rid of this codepath once we get rid of the incremental compositing update in RenderLayer::styleChanged. + if (m_renderView.document().lifecycle().state() < DocumentLifecycle::LayoutClean) + return layer->hasCompositedLayerMapping(); + + bool paintsContent = layer->isVisuallyNonEmpty() || layer->hasVisibleDescendant(); + if (!paintsContent) { + if (viewportConstrainedNotCompositedReason) + *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForNoVisibleContent; + return false; + } + + // Fixed position elements that are invisible in the current view don't get their own layer. + if (FrameView* frameView = m_renderView.frameView()) { + ASSERT(m_renderView.document().lifecycle().state() == DocumentLifecycle::InCompositingUpdate); + LayoutRect viewBounds = frameView->viewportConstrainedVisibleContentRect(); + LayoutRect layerBounds = layer->boundingBoxForCompositing(layer->compositor()->rootRenderLayer(), RenderLayer::ApplyBoundsChickenEggHacks); + if (!viewBounds.intersects(enclosingIntRect(layerBounds))) { + if (viewportConstrainedNotCompositedReason) + *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForBoundsOutOfView; + return false; + } + } + + return true; +} + +} diff --git a/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingReasonFinder.h b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingReasonFinder.h new file mode 100644 index 00000000000..dce877b3fee --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingReasonFinder.h @@ -0,0 +1,47 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CompositingReasonFinder_h +#define CompositingReasonFinder_h + +#include "core/rendering/RenderLayer.h" +#include "core/rendering/compositing/CompositingTriggers.h" +#include "platform/graphics/CompositingReasons.h" + +namespace WebCore { + +class RenderObject; +class RenderView; + +class CompositingReasonFinder { + WTF_MAKE_NONCOPYABLE(CompositingReasonFinder); +public: + explicit CompositingReasonFinder(RenderView&); + + CompositingReasons styleDeterminedReasons(RenderObject*) const; + CompositingReasons directReasons(const RenderLayer*) const; + + void updateTriggers(); + + bool hasOverflowScrollTrigger() const; + + bool requiresCompositingForScrollableFrame() const; + bool requiresCompositingForPositionFixed(RenderObject*, const RenderLayer*, RenderLayer::ViewportConstrainedNotCompositedReason*) const; + +private: + bool isMainFrame() const; + + CompositingReasons nonStyleDeterminedDirectReasons(const RenderLayer*) const; + + bool requiresCompositingForTransform(RenderObject*) const; + bool requiresCompositingForFilters(RenderObject*) const; + bool requiresCompositingForAnimation(RenderStyle*) const; + + RenderView& m_renderView; + CompositingTriggerFlags m_compositingTriggers; +}; + +} // namespace WebCore + +#endif // CompositingReasonFinder_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingRequirementsUpdater.cpp b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingRequirementsUpdater.cpp new file mode 100644 index 00000000000..f44d52d0472 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingRequirementsUpdater.cpp @@ -0,0 +1,460 @@ +/* + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2014 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 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 "core/rendering/compositing/CompositingRequirementsUpdater.h" + +#include "core/rendering/RenderLayerStackingNode.h" +#include "core/rendering/RenderLayerStackingNodeIterator.h" +#include "core/rendering/RenderView.h" +#include "core/rendering/compositing/RenderLayerCompositor.h" +#include "platform/TraceEvent.h" + +namespace WebCore { + +class OverlapMapContainer { +public: + void add(const IntRect& bounds) + { + m_layerRects.append(bounds); + m_boundingBox.unite(bounds); + } + + bool overlapsLayers(const IntRect& bounds) const + { + // Checking with the bounding box will quickly reject cases when + // layers are created for lists of items going in one direction and + // never overlap with each other. + if (!bounds.intersects(m_boundingBox)) + return false; + for (unsigned i = 0; i < m_layerRects.size(); i++) { + if (m_layerRects[i].intersects(bounds)) + return true; + } + return false; + } + + void unite(const OverlapMapContainer& otherContainer) + { + m_layerRects.appendVector(otherContainer.m_layerRects); + m_boundingBox.unite(otherContainer.m_boundingBox); + } +private: + Vector<IntRect, 64> m_layerRects; + IntRect m_boundingBox; +}; + +class CompositingRequirementsUpdater::OverlapMap { + WTF_MAKE_NONCOPYABLE(OverlapMap); +public: + OverlapMap() + { + // Begin by assuming the root layer will be composited so that there + // is something on the stack. The root layer should also never get a + // finishCurrentOverlapTestingContext() call. + beginNewOverlapTestingContext(); + } + + void add(RenderLayer* layer, const IntRect& bounds) + { + ASSERT(!layer->isRootLayer()); + if (bounds.isEmpty()) + return; + + // Layers do not contribute to overlap immediately--instead, they will + // contribute to overlap as soon as they have been recursively processed + // and popped off the stack. + ASSERT(m_overlapStack.size() >= 2); + m_overlapStack[m_overlapStack.size() - 2].add(bounds); + } + + bool overlapsLayers(const IntRect& bounds) const + { + return m_overlapStack.last().overlapsLayers(bounds); + } + + void beginNewOverlapTestingContext() + { + // This effectively creates a new "clean slate" for overlap state. + // This is used when we know that a subtree or remaining set of + // siblings does not need to check overlap with things behind it. + m_overlapStack.append(OverlapMapContainer()); + } + + void finishCurrentOverlapTestingContext() + { + // The overlap information on the top of the stack is still necessary + // for checking overlap of any layers outside this context that may + // overlap things from inside this context. Therefore, we must merge + // the information from the top of the stack before popping the stack. + // + // FIXME: we may be able to avoid this deep copy by rearranging how + // overlapMap state is managed. + m_overlapStack[m_overlapStack.size() - 2].unite(m_overlapStack.last()); + m_overlapStack.removeLast(); + } + +private: + Vector<OverlapMapContainer> m_overlapStack; +}; + +class CompositingRequirementsUpdater::RecursionData { +public: + RecursionData(RenderLayer* compAncestor, bool testOverlap) + : m_compositingAncestor(compAncestor) + , m_subtreeIsCompositing(false) + , m_hasUnisolatedCompositedBlendingDescendant(false) + , m_testingOverlap(testOverlap) +#ifndef NDEBUG + , m_depth(0) +#endif + { + } + + RecursionData(const RecursionData& other) + : m_compositingAncestor(other.m_compositingAncestor) + , m_subtreeIsCompositing(other.m_subtreeIsCompositing) + , m_hasUnisolatedCompositedBlendingDescendant(other.m_hasUnisolatedCompositedBlendingDescendant) + , m_testingOverlap(other.m_testingOverlap) +#ifndef NDEBUG + , m_depth(other.m_depth + 1) +#endif + { + } + + RenderLayer* m_compositingAncestor; + bool m_subtreeIsCompositing; + bool m_hasUnisolatedCompositedBlendingDescendant; + bool m_testingOverlap; +#ifndef NDEBUG + int m_depth; +#endif +}; + +static bool requiresCompositingOrSquashing(CompositingReasons reasons) +{ +#ifndef NDEBUG + bool fastAnswer = reasons != CompositingReasonNone; + bool slowAnswer = requiresCompositing(reasons) || requiresSquashing(reasons); + ASSERT(fastAnswer == slowAnswer); +#endif + return reasons != CompositingReasonNone; +} + +static CompositingReasons subtreeReasonsForCompositing(RenderObject* renderer, bool hasCompositedDescendants, bool has3DTransformedDescendants) +{ + CompositingReasons subtreeReasons = CompositingReasonNone; + + // FIXME: this seems to be a potentially different layer than the layer for which this was called. May not be an error, but is very confusing. + RenderLayer* layer = toRenderBoxModelObject(renderer)->layer(); + + // When a layer has composited descendants, some effects, like 2d transforms, filters, masks etc must be implemented + // via compositing so that they also apply to those composited descdendants. + if (hasCompositedDescendants) { + if (layer->transform()) + subtreeReasons |= CompositingReasonTransformWithCompositedDescendants; + + if (layer->shouldIsolateCompositedDescendants()) { + ASSERT(layer->stackingNode()->isStackingContext()); + subtreeReasons |= CompositingReasonIsolateCompositedDescendants; + } + + // If the implementation of createsGroup changes, we need to be aware of that in this part of code. + ASSERT((renderer->isTransparent() || renderer->hasMask() || renderer->hasFilter() || renderer->hasBlendMode()) == renderer->createsGroup()); + if (renderer->isTransparent()) + subtreeReasons |= CompositingReasonOpacityWithCompositedDescendants; + if (renderer->hasMask()) + subtreeReasons |= CompositingReasonMaskWithCompositedDescendants; + if (renderer->hasFilter()) + subtreeReasons |= CompositingReasonFilterWithCompositedDescendants; + if (renderer->hasBlendMode()) + subtreeReasons |= CompositingReasonBlendingWithCompositedDescendants; + + if (renderer->hasReflection()) + subtreeReasons |= CompositingReasonReflectionWithCompositedDescendants; + + if (renderer->hasClipOrOverflowClip()) + subtreeReasons |= CompositingReasonClipsCompositingDescendants; + } + + // A layer with preserve-3d or perspective only needs to be composited if there are descendant layers that + // will be affected by the preserve-3d or perspective. + if (has3DTransformedDescendants) { + if (renderer->style()->transformStyle3D() == TransformStyle3DPreserve3D) + subtreeReasons |= CompositingReasonPreserve3DWith3DDescendants; + + if (renderer->style()->hasPerspective()) + subtreeReasons |= CompositingReasonPerspectiveWith3DDescendants; + } + + return subtreeReasons; +} + +CompositingRequirementsUpdater::CompositingRequirementsUpdater(RenderView& renderView, CompositingReasonFinder& compositingReasonFinder) + : m_renderView(renderView) + , m_compositingReasonFinder(compositingReasonFinder) +{ +} + +CompositingRequirementsUpdater::~CompositingRequirementsUpdater() +{ +} + +void CompositingRequirementsUpdater::update(RenderLayer* root) +{ + TRACE_EVENT0("blink_rendering", "CompositingRequirementsUpdater::updateRecursive"); + + // 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. + RecursionData recursionData(root, true); + OverlapMap overlapTestRequestMap; + bool saw3DTransform = false; + + // FIXME: Passing these unclippedDescendants down and keeping track + // of them dynamically, we are requiring a full tree walk. This + // should be removed as soon as proper overlap testing based on + // scrolling and animation bounds is implemented (crbug.com/252472). + Vector<RenderLayer*> unclippedDescendants; + IntRect absoluteDecendantBoundingBox; + updateRecursive(0, root, overlapTestRequestMap, recursionData, saw3DTransform, unclippedDescendants, absoluteDecendantBoundingBox); +} + +void CompositingRequirementsUpdater::updateRecursive(RenderLayer* ancestorLayer, RenderLayer* layer, OverlapMap& overlapMap, RecursionData& currentRecursionData, bool& descendantHas3DTransform, Vector<RenderLayer*>& unclippedDescendants, IntRect& absoluteDecendantBoundingBox) +{ + RenderLayerCompositor* compositor = m_renderView.compositor(); + + layer->stackingNode()->updateLayerListsIfNeeded(); + + CompositingReasons reasonsToComposite = CompositingReasonNone; + CompositingReasons directReasons = m_compositingReasonFinder.directReasons(layer); + + // Video is special. It's the only RenderLayer type that can both have + // RenderLayer children and whose children can't use its backing to render + // into. These children (the controls) always need to be promoted into their + // own layers to draw on top of the accelerated video. + if (currentRecursionData.m_compositingAncestor && currentRecursionData.m_compositingAncestor->renderer()->isVideo()) + directReasons |= CompositingReasonVideoOverlay; + + if (compositor->canBeComposited(layer)) + reasonsToComposite |= directReasons; + + // Next, accumulate reasons related to overlap. + // If overlap testing is used, this reason will be overridden. If overlap testing is not + // used, we must assume we overlap if there is anything composited behind us in paint-order. + CompositingReasons overlapCompositingReason = currentRecursionData.m_subtreeIsCompositing ? CompositingReasonAssumedOverlap : CompositingReasonNone; + + if (m_renderView.compositor()->acceleratedCompositingForOverflowScrollEnabled()) { + Vector<size_t> unclippedDescendantsToRemove; + for (size_t i = 0; i < unclippedDescendants.size(); i++) { + RenderLayer* unclippedDescendant = unclippedDescendants.at(i); + // If we've reached the containing block of one of the unclipped + // descendants, that element is no longer relevant to whether or not we + // should opt in. Unfortunately we can't easily remove from the list + // while we're iterating, so we have to store it for later removal. + if (unclippedDescendant->renderer()->containingBlock() == layer->renderer()) { + unclippedDescendantsToRemove.append(i); + continue; + } + if (layer->scrollsWithRespectTo(unclippedDescendant)) + reasonsToComposite |= CompositingReasonAssumedOverlap; + } + + // Remove irrelevant unclipped descendants in reverse order so our stored + // indices remain valid. + for (size_t i = 0; i < unclippedDescendantsToRemove.size(); i++) + unclippedDescendants.remove(unclippedDescendantsToRemove.at(unclippedDescendantsToRemove.size() - i - 1)); + + if (reasonsToComposite & CompositingReasonOutOfFlowClipping) + unclippedDescendants.append(layer); + } + + const IntRect& absBounds = layer->compositingInputs().clippedAbsoluteBoundingBox; + absoluteDecendantBoundingBox = absBounds; + + if (currentRecursionData.m_testingOverlap && !requiresCompositingOrSquashing(directReasons)) + overlapCompositingReason = overlapMap.overlapsLayers(absBounds) ? CompositingReasonOverlap : CompositingReasonNone; + + reasonsToComposite |= overlapCompositingReason; + + // 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. + RecursionData childRecursionData(currentRecursionData); + childRecursionData.m_subtreeIsCompositing = false; + + bool willBeCompositedOrSquashed = compositor->canBeComposited(layer) && requiresCompositingOrSquashing(reasonsToComposite); + if (willBeCompositedOrSquashed) { + // Tell the parent it has compositing descendants. + currentRecursionData.m_subtreeIsCompositing = true; + // This layer now acts as the ancestor for kids. + childRecursionData.m_compositingAncestor = layer; + + // Here we know that all children and the layer's own contents can blindly paint into + // this layer's backing, until a descendant is composited. So, we don't need to check + // for overlap with anything behind this layer. + overlapMap.beginNewOverlapTestingContext(); + // This layer is going to be composited, so children can safely ignore the fact that there's an + // animation running behind this layer, meaning they can rely on the overlap map testing again. + childRecursionData.m_testingOverlap = true; + } + +#if ASSERT_ENABLED + LayerListMutationDetector mutationChecker(layer->stackingNode()); +#endif + + bool anyDescendantHas3DTransform = false; + bool willHaveForegroundLayer = false; + + if (layer->stackingNode()->isStackingContext()) { + RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NegativeZOrderChildren); + while (RenderLayerStackingNode* curNode = iterator.next()) { + IntRect absoluteChildDecendantBoundingBox; + updateRecursive(layer, curNode->layer(), overlapMap, childRecursionData, anyDescendantHas3DTransform, unclippedDescendants, absoluteChildDecendantBoundingBox); + absoluteDecendantBoundingBox.unite(absoluteChildDecendantBoundingBox); + + // If we have to make a layer for this child, make one now so we can have a contents layer + // (since we need to ensure that the -ve z-order child renders underneath our contents). + if (childRecursionData.m_subtreeIsCompositing) { + reasonsToComposite |= CompositingReasonNegativeZIndexChildren; + + if (!willBeCompositedOrSquashed) { + // make layer compositing + childRecursionData.m_compositingAncestor = layer; + overlapMap.beginNewOverlapTestingContext(); + willBeCompositedOrSquashed = true; + willHaveForegroundLayer = true; + + // FIXME: temporary solution for the first negative z-index composited child: + // re-compute the absBounds for the child so that we can add the + // negative z-index child's bounds to the new overlap context. + overlapMap.beginNewOverlapTestingContext(); + overlapMap.add(curNode->layer(), curNode->layer()->compositingInputs().clippedAbsoluteBoundingBox); + overlapMap.finishCurrentOverlapTestingContext(); + } + } + } + } + + if (willHaveForegroundLayer) { + ASSERT(willBeCompositedOrSquashed); + // A foreground layer effectively is a new backing for all subsequent children, so + // we don't need to test for overlap with anything behind this. So, we can finish + // the previous context that was accumulating rects for the negative z-index + // children, and start with a fresh new empty context. + overlapMap.finishCurrentOverlapTestingContext(); + overlapMap.beginNewOverlapTestingContext(); + // This layer is going to be composited, so children can safely ignore the fact that there's an + // animation running behind this layer, meaning they can rely on the overlap map testing again + childRecursionData.m_testingOverlap = true; + } + + RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren); + while (RenderLayerStackingNode* curNode = iterator.next()) { + IntRect absoluteChildDecendantBoundingBox; + updateRecursive(layer, curNode->layer(), overlapMap, childRecursionData, anyDescendantHas3DTransform, unclippedDescendants, absoluteChildDecendantBoundingBox); + absoluteDecendantBoundingBox.unite(absoluteChildDecendantBoundingBox); + } + + // Now that the subtree has been traversed, we can check for compositing reasons that depended on the state of the subtree. + + if (layer->stackingNode()->isStackingContext()) { + layer->setShouldIsolateCompositedDescendants(childRecursionData.m_hasUnisolatedCompositedBlendingDescendant); + } else { + layer->setShouldIsolateCompositedDescendants(false); + currentRecursionData.m_hasUnisolatedCompositedBlendingDescendant = childRecursionData.m_hasUnisolatedCompositedBlendingDescendant; + } + + // Subsequent layers in the parent's stacking context may also need to composite. + if (childRecursionData.m_subtreeIsCompositing) + currentRecursionData.m_subtreeIsCompositing = true; + + // Set the flag to say that this SC has compositing children. + layer->setHasCompositingDescendant(childRecursionData.m_subtreeIsCompositing); + + if (layer->isRootLayer()) { + // The root layer needs to be composited if anything else in the tree is composited. + // Otherwise, we can disable compositing entirely. + if (childRecursionData.m_subtreeIsCompositing || requiresCompositingOrSquashing(reasonsToComposite) || compositor->rootShouldAlwaysComposite()) { + reasonsToComposite |= CompositingReasonRoot; + } else { + compositor->setCompositingModeEnabled(false); + reasonsToComposite = CompositingReasonNone; + } + } else { + // All layers (even ones that aren't being composited) need to get added to + // the overlap map. Layers that are not separately composited will paint into their + // compositing ancestor's backing, and so are still considered for overlap. + if (childRecursionData.m_compositingAncestor && !childRecursionData.m_compositingAncestor->isRootLayer()) + overlapMap.add(layer, absBounds); + + // Now check for reasons to become composited that depend on the state of descendant layers. + CompositingReasons subtreeCompositingReasons = subtreeReasonsForCompositing(layer->renderer(), childRecursionData.m_subtreeIsCompositing, anyDescendantHas3DTransform); + reasonsToComposite |= subtreeCompositingReasons; + if (!willBeCompositedOrSquashed && compositor->canBeComposited(layer) && requiresCompositingOrSquashing(subtreeCompositingReasons)) { + childRecursionData.m_compositingAncestor = layer; + // FIXME: this context push is effectively a no-op but needs to exist for + // now, because the code is designed to push overlap information to the + // second-from-top context of the stack. + overlapMap.beginNewOverlapTestingContext(); + overlapMap.add(layer, absoluteDecendantBoundingBox); + willBeCompositedOrSquashed = true; + } + + // If the original layer is composited, the reflection needs to be, too. + if (layer->reflectionInfo()) { + // FIXME: Shouldn't we call computeCompositingRequirements to handle a reflection overlapping with another renderer? + RenderLayer* reflectionLayer = layer->reflectionInfo()->reflectionLayer(); + CompositingReasons reflectionCompositingReason = willBeCompositedOrSquashed ? CompositingReasonReflectionOfCompositedParent : CompositingReasonNone; + reflectionLayer->setCompositingReasons(reflectionLayer->compositingReasons() | reflectionCompositingReason); + } + + if (willBeCompositedOrSquashed && layer->blendInfo().hasBlendMode()) + currentRecursionData.m_hasUnisolatedCompositedBlendingDescendant = true; + + // Turn overlap testing off for later layers if it's already off, or if we have an animating transform. + // Note that if the layer clips its descendants, there's no reason to propagate the child animation to the parent layers. That's because + // we know for sure the animation is contained inside the clipping rectangle, which is already added to the overlap map. + bool isCompositedClippingLayer = compositor->canBeComposited(layer) && (reasonsToComposite & CompositingReasonClipsCompositingDescendants); + if ((!childRecursionData.m_testingOverlap && !isCompositedClippingLayer) || isRunningAcceleratedTransformAnimation(layer->renderer())) + currentRecursionData.m_testingOverlap = false; + + if (childRecursionData.m_compositingAncestor == layer) + overlapMap.finishCurrentOverlapTestingContext(); + + descendantHas3DTransform |= anyDescendantHas3DTransform || layer->has3DTransform(); + } + + // At this point we have finished collecting all reasons to composite this layer. + layer->setCompositingReasons(reasonsToComposite); + +} + +bool CompositingRequirementsUpdater::isRunningAcceleratedTransformAnimation(RenderObject* renderer) const +{ + return renderer->style()->hasCurrentTransformAnimation(); +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingRequirementsUpdater.h b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingRequirementsUpdater.h new file mode 100644 index 00000000000..09f219fb002 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingRequirementsUpdater.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2014 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 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 CompositingRequirementsUpdater_h +#define CompositingRequirementsUpdater_h + +#include "platform/geometry/IntRect.h" +#include "platform/graphics/CompositingReasons.h" +#include "wtf/Vector.h" + +namespace WebCore { + +class CompositingReasonFinder; +class RenderLayer; +class RenderObject; +class RenderView; + +class CompositingRequirementsUpdater { +public: + CompositingRequirementsUpdater(RenderView&, CompositingReasonFinder&); + ~CompositingRequirementsUpdater(); + + // Recurse through the layers in z-index and overflow order (which is equivalent to painting order) + // For the z-order children of a compositing layer: + // If a child layers has a compositing layer, then all subsequent layers must + // be compositing in order to render above that layer. + // + // If a child in the negative z-order list is compositing, then the layer itself + // must be compositing so that its contents render over that child. + // This implies that its positive z-index children must also be compositing. + // + void update(RenderLayer* root); + +private: + class OverlapMap; + class RecursionData; + + void updateRecursive(RenderLayer* ancestorLayer, RenderLayer* currentLayer, OverlapMap&, RecursionData&, bool& descendantHas3DTransform, Vector<RenderLayer*>& unclippedDescendants, IntRect& absoluteDecendantBoundingBox); + bool isRunningAcceleratedTransformAnimation(RenderObject*) const; + + RenderView& m_renderView; + CompositingReasonFinder& m_compositingReasonFinder; +}; + +} // namespace WebCore + +#endif // CompositingRequirementsUpdater_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/CompositingState.h b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingState.h index 3873871f304..3873871f304 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/CompositingState.h +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingState.h diff --git a/chromium/third_party/WebKit/Source/core/rendering/BidiRun.cpp b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingTriggers.h index 4af7881a87e..499718864be 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/BidiRun.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/CompositingTriggers.h @@ -1,8 +1,7 @@ -/** - * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple Inc. All rights reserved. - * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) +/* + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple, Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2012 Samsung Electronics. 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 @@ -18,34 +17,25 @@ * 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" -#include "core/rendering/BidiRun.h" -#include "platform/Partitions.h" -#include "wtf/RefCountedLeakCounter.h" - -using namespace WTF; +#ifndef CompositingTriggers_h +#define CompositingTriggers_h namespace WebCore { -DEFINE_DEBUG_ONLY_GLOBAL(RefCountedLeakCounter, bidiRunCounter, ("BidiRun")); +enum CompositingTrigger { + VideoTrigger = 1 << 1, + CanvasTrigger = 1 << 3, + FilterTrigger = 1 << 5, + ScrollableInnerFrameTrigger = 1 << 6, + OverflowScrollTrigger = 1 << 7, + ViewportConstrainedPositionedTrigger = 1 << 8, + AllCompositingTriggers = 0xFFFFFFFF, +}; -void* BidiRun::operator new(size_t sz) -{ -#ifndef NDEBUG - bidiRunCounter.increment(); -#endif - return partitionAlloc(Partitions::getRenderingPartition(), sz); -} +typedef unsigned CompositingTriggerFlags; -void BidiRun::operator delete(void* ptr) -{ -#ifndef NDEBUG - bidiRunCounter.decrement(); -#endif - partitionFree(ptr); } -} +#endif diff --git a/chromium/third_party/WebKit/Source/core/rendering/compositing/GraphicsLayerTreeBuilder.cpp b/chromium/third_party/WebKit/Source/core/rendering/compositing/GraphicsLayerTreeBuilder.cpp new file mode 100644 index 00000000000..9826be1185e --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/GraphicsLayerTreeBuilder.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2014 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 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 "core/rendering/compositing/GraphicsLayerTreeBuilder.h" + +#include "core/html/HTMLMediaElement.h" +#include "core/rendering/RenderLayer.h" +#include "core/rendering/RenderLayerReflectionInfo.h" +#include "core/rendering/RenderPart.h" +#include "core/rendering/RenderView.h" +#include "core/rendering/compositing/CompositedLayerMapping.h" +#include "core/rendering/compositing/RenderLayerCompositor.h" + +namespace WebCore { + +GraphicsLayerTreeBuilder::GraphicsLayerTreeBuilder() +{ +} + +GraphicsLayerTreeBuilder::~GraphicsLayerTreeBuilder() +{ +} + +static bool shouldAppendLayer(const RenderLayer& layer) +{ + if (!RuntimeEnabledFeatures::overlayFullscreenVideoEnabled()) + return true; + Node* node = layer.renderer()->node(); + if (node && isHTMLMediaElement(*node) && toHTMLMediaElement(node)->isFullscreen()) + return false; + return true; +} + +void GraphicsLayerTreeBuilder::rebuild(RenderLayer& layer, GraphicsLayerVector& childLayersOfEnclosingLayer) +{ + // 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 + // have been processed. computeCompositingRequirements() will already have done the repaint if necessary. + + layer.stackingNode()->updateLayerListsIfNeeded(); + + const bool hasCompositedLayerMapping = layer.hasCompositedLayerMapping(); + CompositedLayerMappingPtr currentCompositedLayerMapping = layer.compositedLayerMapping(); + + // If this layer has a compositedLayerMapping, then that is where we place subsequent children GraphicsLayers. + // Otherwise children continue to append to the child list of the enclosing layer. + GraphicsLayerVector layerChildren; + GraphicsLayerVector& childList = hasCompositedLayerMapping ? layerChildren : childLayersOfEnclosingLayer; + +#if ASSERT_ENABLED + LayerListMutationDetector mutationChecker(layer.stackingNode()); +#endif + + if (layer.stackingNode()->isStackingContext()) { + RenderLayerStackingNodeIterator iterator(*layer.stackingNode(), NegativeZOrderChildren); + while (RenderLayerStackingNode* curNode = iterator.next()) + rebuild(*curNode->layer(), childList); + + // If a negative z-order child is compositing, we get a foreground layer which needs to get parented. + if (hasCompositedLayerMapping && currentCompositedLayerMapping->foregroundLayer()) + childList.append(currentCompositedLayerMapping->foregroundLayer()); + } + + RenderLayerStackingNodeIterator iterator(*layer.stackingNode(), NormalFlowChildren | PositiveZOrderChildren); + while (RenderLayerStackingNode* curNode = iterator.next()) + rebuild(*curNode->layer(), childList); + + if (hasCompositedLayerMapping) { + bool parented = false; + if (layer.renderer()->isRenderPart()) + parented = RenderLayerCompositor::parentFrameContentLayers(toRenderPart(layer.renderer())); + + if (!parented) + currentCompositedLayerMapping->parentForSublayers()->setChildren(layerChildren); + + // If the layer has a clipping layer the overflow controls layers will be siblings of the clipping layer. + // Otherwise, the overflow control layers are normal children. + if (!currentCompositedLayerMapping->hasClippingLayer() && !currentCompositedLayerMapping->hasScrollingLayer()) { + if (GraphicsLayer* overflowControlLayer = currentCompositedLayerMapping->layerForHorizontalScrollbar()) { + overflowControlLayer->removeFromParent(); + currentCompositedLayerMapping->parentForSublayers()->addChild(overflowControlLayer); + } + + if (GraphicsLayer* overflowControlLayer = currentCompositedLayerMapping->layerForVerticalScrollbar()) { + overflowControlLayer->removeFromParent(); + currentCompositedLayerMapping->parentForSublayers()->addChild(overflowControlLayer); + } + + if (GraphicsLayer* overflowControlLayer = currentCompositedLayerMapping->layerForScrollCorner()) { + overflowControlLayer->removeFromParent(); + currentCompositedLayerMapping->parentForSublayers()->addChild(overflowControlLayer); + } + } + + if (shouldAppendLayer(layer)) + childLayersOfEnclosingLayer.append(currentCompositedLayerMapping->childForSuperlayers()); + } +} + +} diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderBoxRegionInfo.h b/chromium/third_party/WebKit/Source/core/rendering/compositing/GraphicsLayerTreeBuilder.h index 3bde47e9477..4389ebe7f83 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderBoxRegionInfo.h +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/GraphicsLayerTreeBuilder.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2014 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,37 +24,24 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef GraphicsLayerTreeBuilder_h +#define GraphicsLayerTreeBuilder_h -#ifndef RenderBoxRegionInfo_h -#define RenderBoxRegionInfo_h - -#include "platform/LayoutUnit.h" -#include "wtf/FastAllocBase.h" +#include "platform/graphics/GraphicsLayer.h" +#include "wtf/Vector.h" namespace WebCore { -class RenderBoxRegionInfo { - WTF_MAKE_FAST_ALLOCATED; -public: - RenderBoxRegionInfo(LayoutUnit logicalLeft, LayoutUnit logicalWidth, bool isShifted) - : m_logicalLeft(logicalLeft) - , m_logicalWidth(logicalWidth) - , m_isShifted(isShifted) - { } - - LayoutUnit logicalLeft() const { return m_logicalLeft; } - LayoutUnit logicalWidth() const { return m_logicalWidth; } +class RenderLayer; - void shiftLogicalLeft(LayoutUnit delta) { m_logicalLeft += delta; m_isShifted = true; } - - bool isShifted() const { return m_isShifted; } +class GraphicsLayerTreeBuilder { +public: + GraphicsLayerTreeBuilder(); + ~GraphicsLayerTreeBuilder(); -private: - LayoutUnit m_logicalLeft; - LayoutUnit m_logicalWidth; - bool m_isShifted; + void rebuild(RenderLayer&, GraphicsLayerVector& childLayersOfEnclosingLayer); }; } // namespace WebCore -#endif // RenderBoxRegionInfo_h +#endif // GraphicsLayerTreeBuilder_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/compositing/GraphicsLayerUpdater.cpp b/chromium/third_party/WebKit/Source/core/rendering/compositing/GraphicsLayerUpdater.cpp new file mode 100644 index 00000000000..ab9428cef19 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/GraphicsLayerUpdater.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2014 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 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 "core/rendering/compositing/GraphicsLayerUpdater.h" + +#include "core/html/HTMLMediaElement.h" +#include "core/rendering/RenderLayer.h" +#include "core/rendering/RenderLayerReflectionInfo.h" +#include "core/rendering/RenderPart.h" +#include "core/rendering/compositing/CompositedLayerMapping.h" +#include "core/rendering/compositing/RenderLayerCompositor.h" + +namespace WebCore { + +GraphicsLayerUpdater::UpdateContext::UpdateContext(const UpdateContext& other, const RenderLayer& layer) + : m_compositingStackingContext(other.m_compositingStackingContext) + , m_compositingAncestor(other.compositingContainer(layer)) +{ + CompositingState compositingState = layer.compositingState(); + if (compositingState != NotComposited && compositingState != PaintsIntoGroupedBacking) { + m_compositingAncestor = &layer; + if (layer.stackingNode()->isStackingContext()) + m_compositingStackingContext = &layer; + } +} + +const RenderLayer* GraphicsLayerUpdater::UpdateContext::compositingContainer(const RenderLayer& layer) const +{ + return layer.stackingNode()->isNormalFlowOnly() ? m_compositingAncestor : m_compositingStackingContext; +} + +GraphicsLayerUpdater::GraphicsLayerUpdater() + : m_needsRebuildTree(false) +{ +} + +GraphicsLayerUpdater::~GraphicsLayerUpdater() +{ +} + +void GraphicsLayerUpdater::update(Vector<RenderLayer*>& layersNeedingPaintInvalidation, RenderLayer& layer, UpdateType updateType, const UpdateContext& context) +{ + if (layer.hasCompositedLayerMapping()) { + CompositedLayerMappingPtr mapping = layer.compositedLayerMapping(); + + const RenderLayer* compositingContainer = context.compositingContainer(layer); + ASSERT(compositingContainer == layer.ancestorCompositingLayer()); + if (mapping->updateRequiresOwnBackingStoreForAncestorReasons(compositingContainer)) + updateType = ForceUpdate; + + // Note carefully: here we assume that the compositing state of all descendants have been updated already, + // so it is legitimate to compute and cache the composited bounds for this layer. + mapping->updateCompositedBounds(updateType); + + if (RenderLayerReflectionInfo* reflection = layer.reflectionInfo()) { + if (reflection->reflectionLayer()->hasCompositedLayerMapping()) + reflection->reflectionLayer()->compositedLayerMapping()->updateCompositedBounds(ForceUpdate); + } + + if (mapping->updateGraphicsLayerConfiguration(updateType)) + m_needsRebuildTree = true; + + mapping->updateGraphicsLayerGeometry(updateType, compositingContainer, layersNeedingPaintInvalidation); + + updateType = mapping->updateTypeForChildren(updateType); + mapping->clearNeedsGraphicsLayerUpdate(); + + if (!layer.parent()) + layer.compositor()->updateRootLayerPosition(); + + if (mapping->hasUnpositionedOverflowControlsLayers()) + layer.scrollableArea()->positionOverflowControls(IntSize()); + } + + UpdateContext childContext(context, layer); + for (RenderLayer* child = layer.firstChild(); child; child = child->nextSibling()) + update(layersNeedingPaintInvalidation, *child, updateType, childContext); +} + +#if ASSERT_ENABLED + +void GraphicsLayerUpdater::assertNeedsToUpdateGraphicsLayerBitsCleared(RenderLayer& layer) +{ + if (layer.hasCompositedLayerMapping()) + layer.compositedLayerMapping()->assertNeedsToUpdateGraphicsLayerBitsCleared(); + + for (RenderLayer* child = layer.firstChild(); child; child = child->nextSibling()) + assertNeedsToUpdateGraphicsLayerBitsCleared(*child); +} + +#endif + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/compositing/GraphicsLayerUpdater.h b/chromium/third_party/WebKit/Source/core/rendering/compositing/GraphicsLayerUpdater.h new file mode 100644 index 00000000000..df992fa91a1 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/GraphicsLayerUpdater.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2014 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 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 GraphicsLayerUpdater_h +#define GraphicsLayerUpdater_h + +#include "platform/graphics/GraphicsLayer.h" + +namespace WebCore { + +class RenderLayer; + +class GraphicsLayerUpdater { + class UpdateContext { + public: + UpdateContext() + : m_compositingStackingContext(0) + , m_compositingAncestor(0) + { + } + + UpdateContext(const UpdateContext&, const RenderLayer&); + + const RenderLayer* compositingContainer(const RenderLayer&) const; + private: + const RenderLayer* m_compositingStackingContext; + const RenderLayer* m_compositingAncestor; + }; + +public: + GraphicsLayerUpdater(); + ~GraphicsLayerUpdater(); + + enum UpdateType { + DoNotForceUpdate, + ForceUpdate, + }; + + void update(Vector<RenderLayer*>& layersNeedingPaintInvalidation, RenderLayer&, UpdateType = DoNotForceUpdate, const UpdateContext& = UpdateContext()); + void rebuildTree(RenderLayer&, GraphicsLayerVector& childLayersOfEnclosingLayer); + + bool needsRebuildTree() const { return m_needsRebuildTree; } + +#if ASSERT_ENABLED + static void assertNeedsToUpdateGraphicsLayerBitsCleared(RenderLayer&); +#endif + +private: + bool m_needsRebuildTree; +}; + +} // namespace WebCore + +#endif // GraphicsLayerUpdater_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp b/chromium/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp new file mode 100644 index 00000000000..5d35300f2a7 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp @@ -0,0 +1,1259 @@ +/* + * Copyright (C) 2009, 2010 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 "core/rendering/compositing/RenderLayerCompositor.h" + +#include "core/animation/DocumentAnimations.h" +#include "core/dom/FullscreenElementStack.h" +#include "core/dom/ScriptForbiddenScope.h" +#include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" +#include "core/frame/Settings.h" +#include "core/html/HTMLIFrameElement.h" +#include "core/inspector/InspectorInstrumentation.h" +#include "core/inspector/InspectorNodeIds.h" +#include "core/page/Chrome.h" +#include "core/page/Page.h" +#include "core/page/scrolling/ScrollingCoordinator.h" +#include "core/rendering/RenderLayerStackingNode.h" +#include "core/rendering/RenderLayerStackingNodeIterator.h" +#include "core/rendering/RenderVideo.h" +#include "core/rendering/RenderView.h" +#include "core/rendering/compositing/CompositedLayerMapping.h" +#include "core/rendering/compositing/CompositingInputsUpdater.h" +#include "core/rendering/compositing/CompositingLayerAssigner.h" +#include "core/rendering/compositing/CompositingRequirementsUpdater.h" +#include "core/rendering/compositing/GraphicsLayerTreeBuilder.h" +#include "core/rendering/compositing/GraphicsLayerUpdater.h" +#include "platform/OverscrollTheme.h" +#include "platform/RuntimeEnabledFeatures.h" +#include "platform/TraceEvent.h" +#include "platform/graphics/GraphicsLayer.h" +#include "public/platform/Platform.h" + +namespace WebCore { + +RenderLayerCompositor::RenderLayerCompositor(RenderView& renderView) + : m_renderView(renderView) + , m_compositingReasonFinder(renderView) + , m_pendingUpdateType(CompositingUpdateNone) + , m_hasAcceleratedCompositing(true) + , m_compositing(false) + , m_rootShouldAlwaysCompositeDirty(true) + , m_needsUpdateFixedBackground(false) + , m_isTrackingRepaints(false) + , m_rootLayerAttachment(RootLayerUnattached) + , m_inOverlayFullscreenVideo(false) +{ + updateAcceleratedCompositingSettings(); +} + +RenderLayerCompositor::~RenderLayerCompositor() +{ + ASSERT(m_rootLayerAttachment == RootLayerUnattached); +} + +bool RenderLayerCompositor::inCompositingMode() const +{ + // FIXME: This should assert that lificycle is >= CompositingClean since + // the last step of updateIfNeeded can set this bit to false. + ASSERT(!m_rootShouldAlwaysCompositeDirty); + return m_compositing; +} + +bool RenderLayerCompositor::staleInCompositingMode() const +{ + return m_compositing; +} + +void RenderLayerCompositor::setCompositingModeEnabled(bool enable) +{ + if (enable == m_compositing) + return; + + m_compositing = enable; + + // RenderPart::requiresAcceleratedCompositing is used to determine self-paintingness + // and bases it's return value for frames on the m_compositing bit here. + if (HTMLFrameOwnerElement* ownerElement = m_renderView.document().ownerElement()) { + if (RenderPart* renderer = ownerElement->renderPart()) + renderer->layer()->updateSelfPaintingLayer(); + } + + if (m_compositing) + ensureRootLayer(); + else + destroyRootLayer(); + + // Compositing also affects the answer to RenderIFrame::requiresAcceleratedCompositing(), so + // we need to schedule a style recalc in our parent document. + if (HTMLFrameOwnerElement* ownerElement = m_renderView.document().ownerElement()) + ownerElement->setNeedsCompositingUpdate(); +} + +void RenderLayerCompositor::enableCompositingModeIfNeeded() +{ + if (!m_rootShouldAlwaysCompositeDirty) + return; + + m_rootShouldAlwaysCompositeDirty = false; + if (m_compositing) + return; + + if (rootShouldAlwaysComposite()) { + // FIXME: Is this needed? It was added in https://bugs.webkit.org/show_bug.cgi?id=26651. + // No tests fail if it's deleted. + setNeedsCompositingUpdate(CompositingUpdateRebuildTree); + setCompositingModeEnabled(true); + } +} + +bool RenderLayerCompositor::rootShouldAlwaysComposite() const +{ + if (!m_hasAcceleratedCompositing) + return false; + return m_renderView.frame()->isMainFrame() || m_compositingReasonFinder.requiresCompositingForScrollableFrame(); +} + +void RenderLayerCompositor::updateAcceleratedCompositingSettings() +{ + m_compositingReasonFinder.updateTriggers(); + m_hasAcceleratedCompositing = m_renderView.document().settings()->acceleratedCompositingEnabled(); + m_rootShouldAlwaysCompositeDirty = true; +} + +bool RenderLayerCompositor::layerSquashingEnabled() const +{ + if (!RuntimeEnabledFeatures::layerSquashingEnabled()) + return false; + if (Settings* settings = m_renderView.document().settings()) + return settings->layerSquashingEnabled(); + return true; +} + +bool RenderLayerCompositor::acceleratedCompositingForOverflowScrollEnabled() const +{ + return m_compositingReasonFinder.hasOverflowScrollTrigger(); +} + +static RenderVideo* findFullscreenVideoRenderer(Document& document) +{ + Element* fullscreenElement = FullscreenElementStack::fullscreenElementFrom(document); + while (fullscreenElement && fullscreenElement->isFrameOwnerElement()) { + Document* contentDocument = toHTMLFrameOwnerElement(fullscreenElement)->contentDocument(); + if (!contentDocument) + return 0; + fullscreenElement = FullscreenElementStack::fullscreenElementFrom(*contentDocument); + } + if (!isHTMLVideoElement(fullscreenElement)) + return 0; + RenderObject* renderer = fullscreenElement->renderer(); + if (!renderer) + return 0; + return toRenderVideo(renderer); +} + +void RenderLayerCompositor::updateIfNeededRecursive() +{ + for (Frame* child = m_renderView.frameView()->frame().tree().firstChild(); child; child = child->tree().nextSibling()) { + if (child->isLocalFrame()) + toLocalFrame(child)->contentRenderer()->compositor()->updateIfNeededRecursive(); + } + + TRACE_EVENT0("blink_rendering", "RenderLayerCompositor::updateIfNeededRecursive"); + + ASSERT(!m_renderView.needsLayout()); + + ScriptForbiddenScope forbidScript; + + // FIXME: enableCompositingModeIfNeeded can trigger a CompositingUpdateRebuildTree, + // which asserts that it's not InCompositingUpdate. + enableCompositingModeIfNeeded(); + + lifecycle().advanceTo(DocumentLifecycle::InCompositingUpdate); + updateIfNeeded(); + lifecycle().advanceTo(DocumentLifecycle::CompositingClean); + + DocumentAnimations::startPendingAnimations(m_renderView.document()); + // TODO: Figure out why this fails on Chrome OS login page. crbug.com/365507 + // ASSERT(lifecycle().state() == DocumentLifecycle::CompositingClean); + +#if ASSERT_ENABLED + assertNoUnresolvedDirtyBits(); + for (Frame* child = m_renderView.frameView()->frame().tree().firstChild(); child; child = child->tree().nextSibling()) { + if (child->isLocalFrame()) + toLocalFrame(child)->contentRenderer()->compositor()->assertNoUnresolvedDirtyBits(); + } +#endif +} + +void RenderLayerCompositor::setNeedsCompositingUpdate(CompositingUpdateType updateType) +{ + ASSERT(updateType != CompositingUpdateNone); + + // FIXME: This function should only set dirty bits. We shouldn't + // enable compositing mode here. + // We check needsLayout here because we don't know if we need to enable + // compositing mode until layout is up-to-date because we need to know + // if this frame scrolls. + // + // NOTE: CastStreamingApiTestWithPixelOutput.RtpStreamError triggers + // an ASSERT when this code is removed. + if (!m_renderView.needsLayout()) + enableCompositingModeIfNeeded(); + + m_pendingUpdateType = std::max(m_pendingUpdateType, updateType); + page()->animator().scheduleVisualUpdate(); + lifecycle().ensureStateAtMost(DocumentLifecycle::LayoutClean); +} + +void RenderLayerCompositor::didLayout() +{ + // FIXME: Technically we only need to do this when the FrameView's + // isScrollable method would return a different value. + m_rootShouldAlwaysCompositeDirty = true; + enableCompositingModeIfNeeded(); + + // FIXME: Rather than marking the entire RenderView as dirty, we should + // track which RenderLayers moved during layout and only dirty those + // specific RenderLayers. + rootRenderLayer()->setNeedsCompositingInputsUpdate(); + setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange); +} + +#if ASSERT_ENABLED + +void RenderLayerCompositor::assertNoUnresolvedDirtyBits() +{ + ASSERT(m_pendingUpdateType == CompositingUpdateNone); + ASSERT(!m_rootShouldAlwaysCompositeDirty); +} + +#endif + +void RenderLayerCompositor::applyOverlayFullscreenVideoAdjustment() +{ + m_inOverlayFullscreenVideo = false; + if (!m_rootContentLayer) + return; + + bool isMainFrame = m_renderView.frame()->isMainFrame(); + RenderVideo* video = findFullscreenVideoRenderer(m_renderView.document()); + if (!video || !video->hasCompositedLayerMapping()) { + if (isMainFrame) { + GraphicsLayer* backgroundLayer = fixedRootBackgroundLayer(); + if (backgroundLayer && !backgroundLayer->parent()) + rootFixedBackgroundsChanged(); + } + return; + } + + GraphicsLayer* videoLayer = video->compositedLayerMapping()->mainGraphicsLayer(); + + // The fullscreen video has layer position equal to its enclosing frame's scroll position because fullscreen container is fixed-positioned. + // We should reset layer position here since we are going to reattach the layer at the very top level. + videoLayer->setPosition(IntPoint()); + + // Only steal fullscreen video layer and clear all other layers if we are the main frame. + if (!isMainFrame) + return; + + m_rootContentLayer->removeAllChildren(); + m_overflowControlsHostLayer->addChild(videoLayer); + if (GraphicsLayer* backgroundLayer = fixedRootBackgroundLayer()) + backgroundLayer->removeFromParent(); + m_inOverlayFullscreenVideo = true; +} + +void RenderLayerCompositor::updateIfNeeded() +{ + CompositingUpdateType updateType = m_pendingUpdateType; + m_pendingUpdateType = CompositingUpdateNone; + + if (!hasAcceleratedCompositing() || updateType == CompositingUpdateNone) + return; + + RenderLayer* updateRoot = rootRenderLayer(); + + Vector<RenderLayer*> layersNeedingRepaint; + + if (updateType >= CompositingUpdateAfterCompositingInputChange) { + bool layersChanged = false; + { + TRACE_EVENT0("blink_rendering", "CompositingInputsUpdater::update"); + CompositingInputsUpdater(updateRoot).update(updateRoot); +#if ASSERT_ENABLED + CompositingInputsUpdater::assertNeedsCompositingInputsUpdateBitsCleared(updateRoot); +#endif + } + + CompositingRequirementsUpdater(m_renderView, m_compositingReasonFinder).update(updateRoot); + + { + TRACE_EVENT0("blink_rendering", "CompositingLayerAssigner::assign"); + CompositingLayerAssigner(this).assign(updateRoot, layersChanged, layersNeedingRepaint); + } + + { + TRACE_EVENT0("blink_rendering", "RenderLayerCompositor::updateAfterCompositingChange"); + if (const FrameView::ScrollableAreaSet* scrollableAreas = m_renderView.frameView()->scrollableAreas()) { + for (FrameView::ScrollableAreaSet::iterator it = scrollableAreas->begin(); it != scrollableAreas->end(); ++it) + (*it)->updateAfterCompositingChange(); + } + } + + if (layersChanged) + updateType = std::max(updateType, CompositingUpdateRebuildTree); + } + + if (updateType != CompositingUpdateNone) { + TRACE_EVENT0("blink_rendering", "GraphicsLayerUpdater::updateRecursive"); + GraphicsLayerUpdater updater; + updater.update(layersNeedingRepaint, *updateRoot); + + if (updater.needsRebuildTree()) + updateType = std::max(updateType, CompositingUpdateRebuildTree); + +#if ASSERT_ENABLED + // FIXME: Move this check to the end of the compositing update. + GraphicsLayerUpdater::assertNeedsToUpdateGraphicsLayerBitsCleared(*updateRoot); +#endif + } + + if (updateType >= CompositingUpdateRebuildTree) { + GraphicsLayerVector childList; + { + TRACE_EVENT0("blink_rendering", "GraphicsLayerTreeBuilder::rebuild"); + GraphicsLayerTreeBuilder().rebuild(*updateRoot, childList); + } + + if (childList.isEmpty()) + destroyRootLayer(); + else + m_rootContentLayer->setChildren(childList); + + if (RuntimeEnabledFeatures::overlayFullscreenVideoEnabled()) + applyOverlayFullscreenVideoAdjustment(); + } + + if (m_needsUpdateFixedBackground) { + rootFixedBackgroundsChanged(); + m_needsUpdateFixedBackground = false; + } + + for (unsigned i = 0; i < layersNeedingRepaint.size(); i++) { + RenderLayer* layer = layersNeedingRepaint[i]; + layer->repainter().computeRepaintRectsIncludingNonCompositingDescendants(); + + repaintOnCompositingChange(layer); + } + + // Inform the inspector that the layer tree has changed. + if (m_renderView.frame()->isMainFrame()) + InspectorInstrumentation::layerTreeDidChange(m_renderView.frame()); +} + +bool RenderLayerCompositor::allocateOrClearCompositedLayerMapping(RenderLayer* layer, const CompositingStateTransitionType compositedLayerUpdate) +{ + bool compositedLayerMappingChanged = false; + bool nonCompositedReasonChanged = updateLayerIfViewportConstrained(layer); + + // FIXME: It would be nice to directly use the layer's compositing reason, + // but allocateOrClearCompositedLayerMapping also gets called without having updated compositing + // requirements fully. + switch (compositedLayerUpdate) { + case AllocateOwnCompositedLayerMapping: + ASSERT(!layer->hasCompositedLayerMapping()); + setCompositingModeEnabled(true); + + // If this layer was previously squashed, we need to remove its reference to a groupedMapping right away, so + // that computing repaint rects will know the layer's correct compositingState. + // FIXME: do we need to also remove the layer from it's location in the squashing list of its groupedMapping? + // Need to create a test where a squashed layer pops into compositing. And also to cover all other + // sorts of compositingState transitions. + layer->setLostGroupedMapping(false); + layer->setGroupedMapping(0); + + // If we need to repaint, do so before allocating the compositedLayerMapping + repaintOnCompositingChange(layer); + layer->ensureCompositedLayerMapping(); + compositedLayerMappingChanged = true; + + // At this time, the ScrollingCooridnator only supports the top-level frame. + if (layer->isRootLayer() && m_renderView.frame()->isMainFrame()) { + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + scrollingCoordinator->frameViewRootLayerDidChange(m_renderView.frameView()); + } + break; + case RemoveOwnCompositedLayerMapping: + // PutInSquashingLayer means you might have to remove the composited layer mapping first. + case PutInSquashingLayer: + if (layer->hasCompositedLayerMapping()) { + // If we're removing the compositedLayerMapping from a reflection, clear the source GraphicsLayer's pointer to + // its replica GraphicsLayer. In practice this should never happen because reflectee and reflection + // are both either composited, or not composited. + if (layer->isReflection()) { + RenderLayer* sourceLayer = toRenderLayerModelObject(layer->renderer()->parent())->layer(); + if (sourceLayer->hasCompositedLayerMapping()) { + ASSERT(sourceLayer->compositedLayerMapping()->mainGraphicsLayer()->replicaLayer() == layer->compositedLayerMapping()->mainGraphicsLayer()); + sourceLayer->compositedLayerMapping()->mainGraphicsLayer()->setReplicatedByLayer(0); + } + } + + layer->clearCompositedLayerMapping(); + compositedLayerMappingChanged = true; + } + + break; + case RemoveFromSquashingLayer: + case NoCompositingStateChange: + // Do nothing. + break; + } + + if (layer->hasCompositedLayerMapping() && layer->compositedLayerMapping()->updateRequiresOwnBackingStoreForIntrinsicReasons()) + compositedLayerMappingChanged = true; + + if (compositedLayerMappingChanged && layer->renderer()->isRenderPart()) { + RenderLayerCompositor* innerCompositor = frameContentsCompositor(toRenderPart(layer->renderer())); + if (innerCompositor && innerCompositor->staleInCompositingMode()) + innerCompositor->updateRootLayerAttachment(); + } + + if (compositedLayerMappingChanged) + layer->clipper().clearClipRectsIncludingDescendants(PaintingClipRects); + + // If a fixed position layer gained/lost a compositedLayerMapping or the reason not compositing it changed, + // the scrolling coordinator needs to recalculate whether it can do fast scrolling. + if (compositedLayerMappingChanged || nonCompositedReasonChanged) { + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + scrollingCoordinator->frameViewFixedObjectsDidChange(m_renderView.frameView()); + } + + return compositedLayerMappingChanged || nonCompositedReasonChanged; +} + +bool RenderLayerCompositor::updateLayerIfViewportConstrained(RenderLayer* layer) +{ + RenderLayer::ViewportConstrainedNotCompositedReason viewportConstrainedNotCompositedReason = RenderLayer::NoNotCompositedReason; + m_compositingReasonFinder.requiresCompositingForPositionFixed(layer->renderer(), layer, &viewportConstrainedNotCompositedReason); + + if (layer->viewportConstrainedNotCompositedReason() != viewportConstrainedNotCompositedReason) { + ASSERT(viewportConstrainedNotCompositedReason == RenderLayer::NoNotCompositedReason || layer->renderer()->style()->position() == FixedPosition); + layer->setViewportConstrainedNotCompositedReason(viewportConstrainedNotCompositedReason); + return true; + } + return false; +} + +// These are temporary hacks to work around chicken-egg issues while we continue to refactor the compositing code. +// See crbug.com/383191 for a list of tests that fail if this method is removed. +void RenderLayerCompositor::applyUpdateLayerCompositingStateChickenEggHacks(RenderLayer* layer, CompositingStateTransitionType compositedLayerUpdate) +{ + if (compositedLayerUpdate != NoCompositingStateChange) { + bool compositedLayerMappingChanged = allocateOrClearCompositedLayerMapping(layer, compositedLayerUpdate); + if (compositedLayerMappingChanged) { + // Repaint rects can only be computed for layers that have already been attached to the + // render tree, but a chicken-egg compositing update can happen before |layer| gets + // attached. Since newly-created renderers don't get parented until they are attached + // (see RenderTreeBuilder::createRendererForElementIfNeeded), we can check for attachment + // by checking for a parent. + if (layer->parent()) + layer->repainter().computeRepaintRectsIncludingNonCompositingDescendants(); + repaintOnCompositingChange(layer); + } + } +} + +void RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer, UpdateLayerCompositingStateOptions options) +{ + layer->setCompositingReasons(layer->styleDeterminedCompositingReasons(), CompositingReasonComboAllStyleDeterminedReasons); + CompositingStateTransitionType compositedLayerUpdate = CompositingLayerAssigner(this).computeCompositedLayerUpdate(layer); + + if (compositedLayerUpdate != NoCompositingStateChange) + setNeedsCompositingUpdate(CompositingUpdateRebuildTree); + + if (options == UseChickenEggHacks) + applyUpdateLayerCompositingStateChickenEggHacks(layer, compositedLayerUpdate); +} + +void RenderLayerCompositor::repaintOnCompositingChange(RenderLayer* layer) +{ + // If the renderer is not attached yet, no need to repaint. + if (layer->renderer() != &m_renderView && !layer->renderer()->parent()) + return; + + layer->repainter().repaintIncludingNonCompositingDescendants(); +} + +// This method assumes that layout is up-to-date, unlike repaintOnCompositingChange(). +void RenderLayerCompositor::repaintInCompositedAncestor(RenderLayer* layer, const LayoutRect& rect) +{ + RenderLayer* compositedAncestor = layer->enclosingCompositingLayerForRepaint(ExcludeSelf); + if (!compositedAncestor) + return; + ASSERT(compositedAncestor->compositingState() == PaintsIntoOwnBacking || compositedAncestor->compositingState() == PaintsIntoGroupedBacking); + + LayoutPoint offset; + layer->convertToLayerCoords(compositedAncestor, offset); + LayoutRect repaintRect = rect; + repaintRect.moveBy(offset); + compositedAncestor->repainter().setBackingNeedsRepaintInRect(repaintRect); +} + +void RenderLayerCompositor::frameViewDidChangeLocation(const IntPoint& contentsOffset) +{ + if (m_overflowControlsHostLayer) + m_overflowControlsHostLayer->setPosition(contentsOffset); +} + +void RenderLayerCompositor::frameViewDidChangeSize() +{ + if (m_containerLayer) { + FrameView* frameView = m_renderView.frameView(); + m_containerLayer->setSize(frameView->unscaledVisibleContentSize()); + + frameViewDidScroll(); + updateOverflowControlsLayers(); + } +} + +enum AcceleratedFixedRootBackgroundHistogramBuckets { + ScrolledMainFrameBucket = 0, + ScrolledMainFrameWithAcceleratedFixedRootBackground = 1, + ScrolledMainFrameWithUnacceleratedFixedRootBackground = 2, + AcceleratedFixedRootBackgroundHistogramMax = 3 +}; + +void RenderLayerCompositor::frameViewDidScroll() +{ + FrameView* frameView = m_renderView.frameView(); + IntPoint scrollPosition = frameView->scrollPosition(); + + if (!m_scrollLayer) + return; + + bool scrollingCoordinatorHandlesOffset = false; + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) { + if (Settings* settings = m_renderView.document().settings()) { + if (m_renderView.frame()->isMainFrame() || settings->compositedScrollingForFramesEnabled()) + scrollingCoordinatorHandlesOffset = scrollingCoordinator->scrollableAreaScrollLayerDidChange(frameView); + } + } + + // Scroll position = scroll minimum + scroll offset. Adjust the layer's + // position to handle whatever the scroll coordinator isn't handling. + // The minimum scroll position is non-zero for RTL pages with overflow. + if (scrollingCoordinatorHandlesOffset) + m_scrollLayer->setPosition(-frameView->minimumScrollPosition()); + else + m_scrollLayer->setPosition(-scrollPosition); + + + blink::Platform::current()->histogramEnumeration("Renderer.AcceleratedFixedRootBackground", + ScrolledMainFrameBucket, + AcceleratedFixedRootBackgroundHistogramMax); +} + +void RenderLayerCompositor::frameViewScrollbarsExistenceDidChange() +{ + if (m_containerLayer) + updateOverflowControlsLayers(); +} + +void RenderLayerCompositor::rootFixedBackgroundsChanged() +{ + if (!supportsFixedRootBackgroundCompositing()) + return; + + // To avoid having to make the fixed root background layer fixed positioned to + // stay put, we position it in the layer tree as follows: + // + // + Overflow controls host + // + LocalFrame clip + // + (Fixed root background) <-- Here. + // + LocalFrame scroll + // + Root content layer + // + Scrollbars + // + // That is, it needs to be the first child of the frame clip, the sibling of + // the frame scroll layer. The compositor does not own the background layer, it + // just positions it (like the foreground layer). + if (GraphicsLayer* backgroundLayer = fixedRootBackgroundLayer()) + m_containerLayer->addChildBelow(backgroundLayer, m_scrollLayer.get()); +} + +bool RenderLayerCompositor::scrollingLayerDidChange(RenderLayer* layer) +{ + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + return scrollingCoordinator->scrollableAreaScrollLayerDidChange(layer->scrollableArea()); + return false; +} + +String RenderLayerCompositor::layerTreeAsText(LayerTreeFlags flags) +{ + ASSERT(lifecycle().state() >= DocumentLifecycle::CompositingClean); + + if (!m_rootContentLayer) + return String(); + + // We skip dumping the scroll and clip layers to keep layerTreeAsText output + // similar between platforms (unless we explicitly request dumping from the + // root. + GraphicsLayer* rootLayer = m_rootContentLayer.get(); + if (flags & LayerTreeIncludesRootLayer) + rootLayer = rootGraphicsLayer(); + + String layerTreeText = rootLayer->layerTreeAsText(flags); + + // The true root layer is not included in the dump, so if we want to report + // its repaint rects, they must be included here. + if (flags & LayerTreeIncludesRepaintRects) + return m_renderView.frameView()->trackedPaintInvalidationRectsAsText() + layerTreeText; + + return layerTreeText; +} + +RenderLayerCompositor* RenderLayerCompositor::frameContentsCompositor(RenderPart* renderer) +{ + if (!renderer->node()->isFrameOwnerElement()) + return 0; + + HTMLFrameOwnerElement* element = toHTMLFrameOwnerElement(renderer->node()); + if (Document* contentDocument = element->contentDocument()) { + if (RenderView* view = contentDocument->renderView()) + return view->compositor(); + } + return 0; +} + +// FIXME: What does this function do? It needs a clearer name. +bool RenderLayerCompositor::parentFrameContentLayers(RenderPart* renderer) +{ + RenderLayerCompositor* innerCompositor = frameContentsCompositor(renderer); + if (!innerCompositor || !innerCompositor->staleInCompositingMode() || innerCompositor->rootLayerAttachment() != RootLayerAttachedViaEnclosingFrame) + return false; + + RenderLayer* layer = renderer->layer(); + if (!layer->hasCompositedLayerMapping()) + return false; + + CompositedLayerMappingPtr compositedLayerMapping = layer->compositedLayerMapping(); + GraphicsLayer* hostingLayer = compositedLayerMapping->parentForSublayers(); + GraphicsLayer* rootLayer = innerCompositor->rootGraphicsLayer(); + if (hostingLayer->children().size() != 1 || hostingLayer->children()[0] != rootLayer) { + hostingLayer->removeAllChildren(); + hostingLayer->addChild(rootLayer); + } + return true; +} + +void RenderLayerCompositor::repaintCompositedLayers() +{ + recursiveRepaintLayer(rootRenderLayer()); +} + +void RenderLayerCompositor::recursiveRepaintLayer(RenderLayer* layer) +{ + // FIXME: This method does not work correctly with transforms. + if (layer->compositingState() == PaintsIntoOwnBacking) { + layer->compositedLayerMapping()->setContentsNeedDisplay(); + // This function is called only when it is desired to repaint the entire compositing graphics layer tree. + // This includes squashing. + layer->compositedLayerMapping()->setSquashingContentsNeedDisplay(); + } + + layer->stackingNode()->updateLayerListsIfNeeded(); + +#if ASSERT_ENABLED + LayerListMutationDetector mutationChecker(layer->stackingNode()); +#endif + + unsigned childrenToVisit = NormalFlowChildren; + if (layer->hasCompositingDescendant()) + childrenToVisit |= PositiveZOrderChildren | NegativeZOrderChildren; + RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), childrenToVisit); + while (RenderLayerStackingNode* curNode = iterator.next()) + recursiveRepaintLayer(curNode->layer()); +} + +RenderLayer* RenderLayerCompositor::rootRenderLayer() const +{ + return m_renderView.layer(); +} + +GraphicsLayer* RenderLayerCompositor::rootGraphicsLayer() const +{ + if (m_overflowControlsHostLayer) + return m_overflowControlsHostLayer.get(); + return m_rootContentLayer.get(); +} + +GraphicsLayer* RenderLayerCompositor::scrollLayer() const +{ + return m_scrollLayer.get(); +} + +GraphicsLayer* RenderLayerCompositor::containerLayer() const +{ + return m_containerLayer.get(); +} + +GraphicsLayer* RenderLayerCompositor::ensureRootTransformLayer() +{ + ASSERT(rootGraphicsLayer()); + + if (!m_rootTransformLayer.get()) { + m_rootTransformLayer = GraphicsLayer::create(graphicsLayerFactory(), this); + m_overflowControlsHostLayer->addChild(m_rootTransformLayer.get()); + m_rootTransformLayer->addChild(m_containerLayer.get()); + updateOverflowControlsLayers(); + } + + return m_rootTransformLayer.get(); +} + +void RenderLayerCompositor::setIsInWindow(bool isInWindow) +{ + if (!staleInCompositingMode()) + return; + + if (isInWindow) { + if (m_rootLayerAttachment != RootLayerUnattached) + return; + + RootLayerAttachment attachment = m_renderView.frame()->isMainFrame() ? RootLayerAttachedViaChromeClient : RootLayerAttachedViaEnclosingFrame; + attachRootLayer(attachment); + } else { + if (m_rootLayerAttachment == RootLayerUnattached) + return; + + detachRootLayer(); + } +} + +void RenderLayerCompositor::updateRootLayerPosition() +{ + if (m_rootContentLayer) { + const IntRect& documentRect = m_renderView.documentRect(); + m_rootContentLayer->setSize(documentRect.size()); + m_rootContentLayer->setPosition(documentRect.location()); +#if USE(RUBBER_BANDING) + if (m_layerForOverhangShadow) + OverscrollTheme::theme()->updateOverhangShadowLayer(m_layerForOverhangShadow.get(), m_rootContentLayer.get()); +#endif + } + if (m_containerLayer) { + FrameView* frameView = m_renderView.frameView(); + m_containerLayer->setSize(frameView->unscaledVisibleContentSize()); + } +} + +void RenderLayerCompositor::updateStyleDeterminedCompositingReasons(RenderLayer* layer) +{ + CompositingReasons reasons = m_compositingReasonFinder.styleDeterminedReasons(layer->renderer()); + layer->setStyleDeterminedCompositingReasons(reasons); +} + +void RenderLayerCompositor::updateDirectCompositingReasons(RenderLayer* layer) +{ + CompositingReasons reasons = m_compositingReasonFinder.directReasons(layer); + layer->setCompositingReasons(reasons, CompositingReasonComboAllDirectReasons); +} + +void RenderLayerCompositor::setOverlayLayer(GraphicsLayer* layer) +{ + ASSERT(rootGraphicsLayer()); + + if (layer->parent() != m_overflowControlsHostLayer.get()) + m_overflowControlsHostLayer->addChild(layer); +} + +bool RenderLayerCompositor::canBeComposited(const RenderLayer* layer) const +{ + // 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->subtreeIsInvisible() && layer->renderer()->flowThreadState() == RenderObject::NotInsideFlowThread; +} + +// 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. +// Thus, a RenderLayer can be clipped by a RenderLayer that is an ancestor in the renderer hierarchy, +// but a sibling in the z-order hierarchy. +bool RenderLayerCompositor::clippedByNonAncestorInStackingTree(const RenderLayer* layer) const +{ + if (!layer->hasCompositedLayerMapping() || !layer->parent()) + return false; + + const RenderLayer* compositingAncestor = layer->ancestorCompositingLayer(); + if (!compositingAncestor) + return false; + + RenderObject* clippingContainer = layer->renderer()->clippingContainer(); + if (!clippingContainer) + return false; + + if (compositingAncestor->renderer()->isDescendantOf(clippingContainer)) + return false; + + return true; +} + +// Return true if the given layer is a stacking context and has compositing child +// layers that it needs to clip. In this case we insert a clipping GraphicsLayer +// into the hierarchy between this layer and its children in the z-order hierarchy. +bool RenderLayerCompositor::clipsCompositingDescendants(const RenderLayer* layer) const +{ + return layer->hasCompositingDescendant() && layer->renderer()->hasClipOrOverflowClip(); +} + +// 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. +bool RenderLayerCompositor::needsContentsCompositingLayer(const RenderLayer* layer) const +{ + return layer->stackingNode()->hasNegativeZOrderList(); +} + +static void paintScrollbar(Scrollbar* scrollbar, GraphicsContext& context, const IntRect& clip) +{ + if (!scrollbar) + return; + + context.save(); + const IntRect& scrollbarRect = scrollbar->frameRect(); + context.translate(-scrollbarRect.x(), -scrollbarRect.y()); + IntRect transformedClip = clip; + transformedClip.moveBy(scrollbarRect.location()); + scrollbar->paint(&context, transformedClip); + context.restore(); +} + +void RenderLayerCompositor::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& context, GraphicsLayerPaintingPhase, const IntRect& clip) +{ + if (graphicsLayer == layerForHorizontalScrollbar()) + paintScrollbar(m_renderView.frameView()->horizontalScrollbar(), context, clip); + else if (graphicsLayer == layerForVerticalScrollbar()) + paintScrollbar(m_renderView.frameView()->verticalScrollbar(), context, clip); + else if (graphicsLayer == layerForScrollCorner()) { + const IntRect& scrollCorner = m_renderView.frameView()->scrollCornerRect(); + context.save(); + context.translate(-scrollCorner.x(), -scrollCorner.y()); + IntRect transformedClip = clip; + transformedClip.moveBy(scrollCorner.location()); + m_renderView.frameView()->paintScrollCorner(&context, transformedClip); + context.restore(); + } +} + +bool RenderLayerCompositor::supportsFixedRootBackgroundCompositing() const +{ + if (Settings* settings = m_renderView.document().settings()) { + if (settings->acceleratedCompositingForFixedRootBackgroundEnabled()) + return true; + } + return false; +} + +bool RenderLayerCompositor::needsFixedRootBackgroundLayer(const RenderLayer* layer) const +{ + if (layer != m_renderView.layer()) + return false; + + return supportsFixedRootBackgroundCompositing() && m_renderView.rootBackgroundIsEntirelyFixed(); +} + +GraphicsLayer* RenderLayerCompositor::fixedRootBackgroundLayer() const +{ + // Get the fixed root background from the RenderView layer's compositedLayerMapping. + RenderLayer* viewLayer = m_renderView.layer(); + if (!viewLayer) + return 0; + + if (viewLayer->compositingState() == PaintsIntoOwnBacking && viewLayer->compositedLayerMapping()->backgroundLayerPaintsFixedRootBackground()) + return viewLayer->compositedLayerMapping()->backgroundLayer(); + + return 0; +} + +static void resetTrackedRepaintRectsRecursive(GraphicsLayer* graphicsLayer) +{ + if (!graphicsLayer) + return; + + graphicsLayer->resetTrackedRepaints(); + + for (size_t i = 0; i < graphicsLayer->children().size(); ++i) + resetTrackedRepaintRectsRecursive(graphicsLayer->children()[i]); + + if (GraphicsLayer* replicaLayer = graphicsLayer->replicaLayer()) + resetTrackedRepaintRectsRecursive(replicaLayer); + + if (GraphicsLayer* maskLayer = graphicsLayer->maskLayer()) + resetTrackedRepaintRectsRecursive(maskLayer); + + if (GraphicsLayer* clippingMaskLayer = graphicsLayer->contentsClippingMaskLayer()) + resetTrackedRepaintRectsRecursive(clippingMaskLayer); +} + +void RenderLayerCompositor::resetTrackedRepaintRects() +{ + if (GraphicsLayer* rootLayer = rootGraphicsLayer()) + resetTrackedRepaintRectsRecursive(rootLayer); +} + +void RenderLayerCompositor::setTracksRepaints(bool tracksRepaints) +{ + ASSERT(lifecycle().state() == DocumentLifecycle::CompositingClean); + m_isTrackingRepaints = tracksRepaints; +} + +bool RenderLayerCompositor::isTrackingRepaints() const +{ + return m_isTrackingRepaints; +} + +static bool shouldCompositeOverflowControls(FrameView* view) +{ + if (Page* page = view->frame().page()) { + if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) + if (scrollingCoordinator->coordinatesScrollingForFrameView(view)) + return true; + } + + return true; +} + +bool RenderLayerCompositor::requiresHorizontalScrollbarLayer() const +{ + FrameView* view = m_renderView.frameView(); + return shouldCompositeOverflowControls(view) && view->horizontalScrollbar(); +} + +bool RenderLayerCompositor::requiresVerticalScrollbarLayer() const +{ + FrameView* view = m_renderView.frameView(); + return shouldCompositeOverflowControls(view) && view->verticalScrollbar(); +} + +bool RenderLayerCompositor::requiresScrollCornerLayer() const +{ + FrameView* view = m_renderView.frameView(); + return shouldCompositeOverflowControls(view) && view->isScrollCornerVisible(); +} + +void RenderLayerCompositor::updateOverflowControlsLayers() +{ +#if USE(RUBBER_BANDING) + if (m_renderView.frame()->isMainFrame()) { + if (!m_layerForOverhangShadow) { + m_layerForOverhangShadow = GraphicsLayer::create(graphicsLayerFactory(), this); + OverscrollTheme::theme()->setUpOverhangShadowLayer(m_layerForOverhangShadow.get()); + OverscrollTheme::theme()->updateOverhangShadowLayer(m_layerForOverhangShadow.get(), m_rootContentLayer.get()); + m_scrollLayer->addChild(m_layerForOverhangShadow.get()); + } + } else { + ASSERT(!m_layerForOverhangShadow); + } +#endif + GraphicsLayer* controlsParent = m_rootTransformLayer.get() ? m_rootTransformLayer.get() : m_overflowControlsHostLayer.get(); + + if (requiresHorizontalScrollbarLayer()) { + if (!m_layerForHorizontalScrollbar) { + m_layerForHorizontalScrollbar = GraphicsLayer::create(graphicsLayerFactory(), this); + } + + if (m_layerForHorizontalScrollbar->parent() != controlsParent) { + controlsParent->addChild(m_layerForHorizontalScrollbar.get()); + + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView.frameView(), HorizontalScrollbar); + } + } else if (m_layerForHorizontalScrollbar) { + m_layerForHorizontalScrollbar->removeFromParent(); + m_layerForHorizontalScrollbar = nullptr; + + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView.frameView(), HorizontalScrollbar); + } + + if (requiresVerticalScrollbarLayer()) { + if (!m_layerForVerticalScrollbar) { + m_layerForVerticalScrollbar = GraphicsLayer::create(graphicsLayerFactory(), this); + } + + if (m_layerForVerticalScrollbar->parent() != controlsParent) { + controlsParent->addChild(m_layerForVerticalScrollbar.get()); + + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView.frameView(), VerticalScrollbar); + } + } else if (m_layerForVerticalScrollbar) { + m_layerForVerticalScrollbar->removeFromParent(); + m_layerForVerticalScrollbar = nullptr; + + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView.frameView(), VerticalScrollbar); + } + + if (requiresScrollCornerLayer()) { + if (!m_layerForScrollCorner) { + m_layerForScrollCorner = GraphicsLayer::create(graphicsLayerFactory(), this); + controlsParent->addChild(m_layerForScrollCorner.get()); + } + } else if (m_layerForScrollCorner) { + m_layerForScrollCorner->removeFromParent(); + m_layerForScrollCorner = nullptr; + } + + m_renderView.frameView()->positionScrollbarLayers(); +} + +void RenderLayerCompositor::ensureRootLayer() +{ + RootLayerAttachment expectedAttachment = m_renderView.frame()->isMainFrame() ? RootLayerAttachedViaChromeClient : RootLayerAttachedViaEnclosingFrame; + if (expectedAttachment == m_rootLayerAttachment) + return; + + if (!m_rootContentLayer) { + m_rootContentLayer = GraphicsLayer::create(graphicsLayerFactory(), this); + IntRect overflowRect = m_renderView.pixelSnappedLayoutOverflowRect(); + m_rootContentLayer->setSize(FloatSize(overflowRect.maxX(), overflowRect.maxY())); + m_rootContentLayer->setPosition(FloatPoint()); + m_rootContentLayer->setOwnerNodeId(InspectorNodeIds::idForNode(m_renderView.generatingNode())); + + // Need to clip to prevent transformed content showing outside this frame + m_rootContentLayer->setMasksToBounds(true); + } + + if (!m_overflowControlsHostLayer) { + ASSERT(!m_scrollLayer); + ASSERT(!m_containerLayer); + + // Create a layer to host the clipping layer and the overflow controls layers. + m_overflowControlsHostLayer = GraphicsLayer::create(graphicsLayerFactory(), this); + + // Create a clipping layer if this is an iframe or settings require to clip. + m_containerLayer = GraphicsLayer::create(graphicsLayerFactory(), this); + bool containerMasksToBounds = !m_renderView.frame()->isMainFrame(); + if (Settings* settings = m_renderView.document().settings()) { + if (settings->mainFrameClipsContent()) + containerMasksToBounds = true; + } + m_containerLayer->setMasksToBounds(containerMasksToBounds); + + m_scrollLayer = GraphicsLayer::create(graphicsLayerFactory(), this); + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + scrollingCoordinator->setLayerIsContainerForFixedPositionLayers(m_scrollLayer.get(), true); + + // Hook them up + m_overflowControlsHostLayer->addChild(m_containerLayer.get()); + m_containerLayer->addChild(m_scrollLayer.get()); + m_scrollLayer->addChild(m_rootContentLayer.get()); + + frameViewDidChangeSize(); + } + + // Check to see if we have to change the attachment + if (m_rootLayerAttachment != RootLayerUnattached) + detachRootLayer(); + + attachRootLayer(expectedAttachment); +} + +void RenderLayerCompositor::destroyRootLayer() +{ + if (!m_rootContentLayer) + return; + + detachRootLayer(); + +#if USE(RUBBER_BANDING) + if (m_layerForOverhangShadow) { + m_layerForOverhangShadow->removeFromParent(); + m_layerForOverhangShadow = nullptr; + } +#endif + + if (m_layerForHorizontalScrollbar) { + m_layerForHorizontalScrollbar->removeFromParent(); + m_layerForHorizontalScrollbar = nullptr; + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView.frameView(), HorizontalScrollbar); + if (Scrollbar* horizontalScrollbar = m_renderView.frameView()->verticalScrollbar()) + m_renderView.frameView()->invalidateScrollbar(horizontalScrollbar, IntRect(IntPoint(0, 0), horizontalScrollbar->frameRect().size())); + } + + if (m_layerForVerticalScrollbar) { + m_layerForVerticalScrollbar->removeFromParent(); + m_layerForVerticalScrollbar = nullptr; + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView.frameView(), VerticalScrollbar); + if (Scrollbar* verticalScrollbar = m_renderView.frameView()->verticalScrollbar()) + m_renderView.frameView()->invalidateScrollbar(verticalScrollbar, IntRect(IntPoint(0, 0), verticalScrollbar->frameRect().size())); + } + + if (m_layerForScrollCorner) { + m_layerForScrollCorner = nullptr; + m_renderView.frameView()->invalidateScrollCorner(m_renderView.frameView()->scrollCornerRect()); + } + + if (m_overflowControlsHostLayer) { + m_overflowControlsHostLayer = nullptr; + m_containerLayer = nullptr; + m_scrollLayer = nullptr; + } + ASSERT(!m_scrollLayer); + m_rootContentLayer = nullptr; + m_rootTransformLayer = nullptr; +} + +void RenderLayerCompositor::attachRootLayer(RootLayerAttachment attachment) +{ + if (!m_rootContentLayer) + return; + + switch (attachment) { + case RootLayerUnattached: + ASSERT_NOT_REACHED(); + break; + case RootLayerAttachedViaChromeClient: { + LocalFrame& frame = m_renderView.frameView()->frame(); + Page* page = frame.page(); + if (!page) + return; + page->chrome().client().attachRootGraphicsLayer(rootGraphicsLayer()); + break; + } + case RootLayerAttachedViaEnclosingFrame: { + HTMLFrameOwnerElement* ownerElement = m_renderView.document().ownerElement(); + ASSERT(ownerElement); + // The layer will get hooked up via CompositedLayerMapping::updateGraphicsLayerConfiguration() + // for the frame's renderer in the parent document. + ownerElement->setNeedsCompositingUpdate(); + break; + } + } + + m_rootLayerAttachment = attachment; +} + +void RenderLayerCompositor::detachRootLayer() +{ + if (!m_rootContentLayer || m_rootLayerAttachment == RootLayerUnattached) + return; + + switch (m_rootLayerAttachment) { + case RootLayerAttachedViaEnclosingFrame: { + // The layer will get unhooked up via CompositedLayerMapping::updateGraphicsLayerConfiguration() + // for the frame's renderer in the parent document. + if (m_overflowControlsHostLayer) + m_overflowControlsHostLayer->removeFromParent(); + else + m_rootContentLayer->removeFromParent(); + + if (HTMLFrameOwnerElement* ownerElement = m_renderView.document().ownerElement()) + ownerElement->setNeedsCompositingUpdate(); + break; + } + case RootLayerAttachedViaChromeClient: { + LocalFrame& frame = m_renderView.frameView()->frame(); + Page* page = frame.page(); + if (!page) + return; + page->chrome().client().attachRootGraphicsLayer(0); + } + break; + case RootLayerUnattached: + break; + } + + m_rootLayerAttachment = RootLayerUnattached; +} + +void RenderLayerCompositor::updateRootLayerAttachment() +{ + ensureRootLayer(); +} + +ScrollingCoordinator* RenderLayerCompositor::scrollingCoordinator() const +{ + if (Page* page = this->page()) + return page->scrollingCoordinator(); + + return 0; +} + +GraphicsLayerFactory* RenderLayerCompositor::graphicsLayerFactory() const +{ + if (Page* page = this->page()) + return page->chrome().client().graphicsLayerFactory(); + return 0; +} + +Page* RenderLayerCompositor::page() const +{ + return m_renderView.frameView()->frame().page(); +} + +DocumentLifecycle& RenderLayerCompositor::lifecycle() const +{ + return m_renderView.document().lifecycle(); +} + +String RenderLayerCompositor::debugName(const GraphicsLayer* graphicsLayer) +{ + String name; + if (graphicsLayer == m_rootContentLayer.get()) { + name = "Content Root Layer"; + } else if (graphicsLayer == m_rootTransformLayer.get()) { + name = "Root Transform Layer"; +#if USE(RUBBER_BANDING) + } else if (graphicsLayer == m_layerForOverhangShadow.get()) { + name = "Overhang Areas Shadow"; +#endif + } else if (graphicsLayer == m_overflowControlsHostLayer.get()) { + name = "Overflow Controls Host Layer"; + } else if (graphicsLayer == m_layerForHorizontalScrollbar.get()) { + name = "Horizontal Scrollbar Layer"; + } else if (graphicsLayer == m_layerForVerticalScrollbar.get()) { + name = "Vertical Scrollbar Layer"; + } else if (graphicsLayer == m_layerForScrollCorner.get()) { + name = "Scroll Corner Layer"; + } else if (graphicsLayer == m_containerLayer.get()) { + name = "LocalFrame Clipping Layer"; + } else if (graphicsLayer == m_scrollLayer.get()) { + name = "LocalFrame Scrolling Layer"; + } else { + ASSERT_NOT_REACHED(); + } + + return name; +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.h b/chromium/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.h new file mode 100644 index 00000000000..4fc1a0456f9 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.h @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2009 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 RenderLayerCompositor_h +#define RenderLayerCompositor_h + +#include "core/page/ChromeClient.h" +#include "core/rendering/RenderLayer.h" +#include "core/rendering/compositing/CompositingReasonFinder.h" +#include "platform/graphics/GraphicsLayerClient.h" +#include "wtf/HashMap.h" + +namespace WebCore { + +class GraphicsLayer; +class RenderPart; +class ScrollingCoordinator; + +enum CompositingUpdateType { + CompositingUpdateNone, + CompositingUpdateAfterGeometryChange, + CompositingUpdateAfterCompositingInputChange, + CompositingUpdateRebuildTree, +}; + +enum CompositingStateTransitionType { + NoCompositingStateChange, + AllocateOwnCompositedLayerMapping, + RemoveOwnCompositedLayerMapping, + PutInSquashingLayer, + RemoveFromSquashingLayer +}; + +// RenderLayerCompositor manages the hierarchy of +// composited RenderLayers. It determines which RenderLayers +// become compositing, and creates and maintains a hierarchy of +// GraphicsLayers based on the RenderLayer painting order. +// +// There is one RenderLayerCompositor per RenderView. + +class RenderLayerCompositor FINAL : public GraphicsLayerClient { + WTF_MAKE_FAST_ALLOCATED; +public: + explicit RenderLayerCompositor(RenderView&); + virtual ~RenderLayerCompositor(); + + void updateIfNeededRecursive(); + + // Return true if this RenderView is in "compositing mode" (i.e. has one or more + // composited RenderLayers) + bool inCompositingMode() const; + // FIXME: Replace all callers with inCompositingMdoe and remove this function. + bool staleInCompositingMode() const; + // This will make a compositing layer at the root automatically, and hook up to + // the native view/window system. + void setCompositingModeEnabled(bool); + + // Returns true if the accelerated compositing is enabled + bool hasAcceleratedCompositing() const { return m_hasAcceleratedCompositing; } + bool layerSquashingEnabled() const; + + bool acceleratedCompositingForOverflowScrollEnabled() const; + + bool rootShouldAlwaysComposite() const; + + // Copy the accelerated compositing related flags from Settings + void updateAcceleratedCompositingSettings(); + + // Used to indicate that a compositing update will be needed for the next frame that gets drawn. + void setNeedsCompositingUpdate(CompositingUpdateType); + + void didLayout(); + + enum UpdateLayerCompositingStateOptions { + Normal, + UseChickenEggHacks, // Use this to trigger temporary chicken-egg hacks. See crbug.com/339892. + }; + + // Update the compositing dirty bits, based on the compositing-impacting properties of the layer. + void updateLayerCompositingState(RenderLayer*, UpdateLayerCompositingStateOptions = Normal); + + // Returns whether this layer is clipped by another layer that is not an ancestor of the given layer in the stacking context hierarchy. + bool clippedByNonAncestorInStackingTree(const RenderLayer*) const; + // Whether layer's compositedLayerMapping needs a GraphicsLayer to clip z-order children of the given RenderLayer. + bool clipsCompositingDescendants(const RenderLayer*) const; + + // Whether the given layer needs an extra 'contents' layer. + bool needsContentsCompositingLayer(const RenderLayer*) const; + + bool supportsFixedRootBackgroundCompositing() const; + bool needsFixedRootBackgroundLayer(const RenderLayer*) const; + GraphicsLayer* fixedRootBackgroundLayer() const; + void setNeedsUpdateFixedBackground() { m_needsUpdateFixedBackground = true; } + + // Repaint the appropriate layers when the given RenderLayer starts or stops being composited. + void repaintOnCompositingChange(RenderLayer*); + + void repaintInCompositedAncestor(RenderLayer*, const LayoutRect&); + void repaintCompositedLayers(); + + RenderLayer* rootRenderLayer() const; + GraphicsLayer* rootGraphicsLayer() const; + GraphicsLayer* scrollLayer() const; + GraphicsLayer* containerLayer() const; + + // We don't always have a root transform layer. This function lazily allocates one + // and returns it as required. + GraphicsLayer* ensureRootTransformLayer(); + + enum RootLayerAttachment { + RootLayerUnattached, + RootLayerAttachedViaChromeClient, + RootLayerAttachedViaEnclosingFrame + }; + + RootLayerAttachment rootLayerAttachment() const { return m_rootLayerAttachment; } + void updateRootLayerAttachment(); + void updateRootLayerPosition(); + + void setIsInWindow(bool); + + static RenderLayerCompositor* frameContentsCompositor(RenderPart*); + // Return true if the layers changed. + static bool parentFrameContentLayers(RenderPart*); + + // Update the geometry of the layers used for clipping and scrolling in frames. + void frameViewDidChangeLocation(const IntPoint& contentsOffset); + void frameViewDidChangeSize(); + void frameViewDidScroll(); + void frameViewScrollbarsExistenceDidChange(); + void rootFixedBackgroundsChanged(); + + bool scrollingLayerDidChange(RenderLayer*); + + String layerTreeAsText(LayerTreeFlags); + + GraphicsLayer* layerForHorizontalScrollbar() const { return m_layerForHorizontalScrollbar.get(); } + GraphicsLayer* layerForVerticalScrollbar() const { return m_layerForVerticalScrollbar.get(); } + GraphicsLayer* layerForScrollCorner() const { return m_layerForScrollCorner.get(); } + + void resetTrackedRepaintRects(); + void setTracksRepaints(bool); + + virtual String debugName(const GraphicsLayer*) OVERRIDE; + + void updateStyleDeterminedCompositingReasons(RenderLayer*); + + // Whether the layer could ever be composited. + bool canBeComposited(const RenderLayer*) const; + + // FIXME: Move allocateOrClearCompositedLayerMapping to CompositingLayerAssigner once we've fixed + // the compositing chicken/egg issues. + bool allocateOrClearCompositedLayerMapping(RenderLayer*, CompositingStateTransitionType compositedLayerUpdate); + + void updateDirectCompositingReasons(RenderLayer*); + + void setOverlayLayer(GraphicsLayer*); + + bool inOverlayFullscreenVideo() const { return m_inOverlayFullscreenVideo; } + +private: + class OverlapMap; + +#if ASSERT_ENABLED + void assertNoUnresolvedDirtyBits(); +#endif + + // Make updates to the layer based on viewport-constrained properties such as position:fixed. This can in turn affect + // compositing. + bool updateLayerIfViewportConstrained(RenderLayer*); + + // GraphicsLayerClient implementation + virtual void notifyAnimationStarted(const GraphicsLayer*, double) OVERRIDE { } + virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect&) OVERRIDE; + + virtual bool isTrackingRepaints() const OVERRIDE; + + // Whether the given RL needs to paint into its own separate backing (and hence would need its own CompositedLayerMapping). + bool needsOwnBacking(const RenderLayer*) const; + + void updateIfNeeded(); + + void recursiveRepaintLayer(RenderLayer*); + + void computeCompositingRequirements(RenderLayer* ancestorLayer, RenderLayer*, OverlapMap&, struct CompositingRecursionData&, bool& descendantHas3DTransform, Vector<RenderLayer*>& unclippedDescendants, IntRect& absoluteDecendantBoundingBox); + + bool hasAnyAdditionalCompositedLayers(const RenderLayer* rootLayer) const; + + void ensureRootLayer(); + void destroyRootLayer(); + + void attachRootLayer(RootLayerAttachment); + void detachRootLayer(); + + void updateOverflowControlsLayers(); + + Page* page() const; + + GraphicsLayerFactory* graphicsLayerFactory() const; + ScrollingCoordinator* scrollingCoordinator() const; + + void enableCompositingModeIfNeeded(); + + bool requiresHorizontalScrollbarLayer() const; + bool requiresVerticalScrollbarLayer() const; + bool requiresScrollCornerLayer() const; + + void applyUpdateLayerCompositingStateChickenEggHacks(RenderLayer*, CompositingStateTransitionType compositedLayerUpdate); + + DocumentLifecycle& lifecycle() const; + + void applyOverlayFullscreenVideoAdjustment(); + + RenderView& m_renderView; + OwnPtr<GraphicsLayer> m_rootContentLayer; + OwnPtr<GraphicsLayer> m_rootTransformLayer; + + CompositingReasonFinder m_compositingReasonFinder; + + CompositingUpdateType m_pendingUpdateType; + + bool m_hasAcceleratedCompositing; + bool m_compositing; + + // The root layer doesn't composite if it's a non-scrollable frame. + // So, after a layout we set this dirty bit to know that we need + // to recompute whether the root layer should composite even if + // none of its descendants composite. + // FIXME: Get rid of all the callers of setCompositingModeEnabled + // except the one in updateIfNeeded, then rename this to + // m_compositingDirty. + bool m_rootShouldAlwaysCompositeDirty; + bool m_needsUpdateFixedBackground; + bool m_isTrackingRepaints; // Used for testing. + + RootLayerAttachment m_rootLayerAttachment; + + // Enclosing container layer, which clips for iframe content + OwnPtr<GraphicsLayer> m_containerLayer; + OwnPtr<GraphicsLayer> m_scrollLayer; + + // Enclosing layer for overflow controls and the clipping layer + OwnPtr<GraphicsLayer> m_overflowControlsHostLayer; + + // Layers for overflow controls + OwnPtr<GraphicsLayer> m_layerForHorizontalScrollbar; + OwnPtr<GraphicsLayer> m_layerForVerticalScrollbar; + OwnPtr<GraphicsLayer> m_layerForScrollCorner; +#if USE(RUBBER_BANDING) + OwnPtr<GraphicsLayer> m_layerForOverhangShadow; +#endif + + bool m_inOverlayFullscreenVideo; +}; + +} // namespace WebCore + +#endif // RenderLayerCompositor_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/line/BreakingContext.cpp b/chromium/third_party/WebKit/Source/core/rendering/line/BreakingContext.cpp new file mode 100644 index 00000000000..513b2c3beaa --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/line/BreakingContext.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2013 Adobe Systems Incorporated. + * + * 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" +#include "core/rendering/line/BreakingContextInlineHeaders.h" + +namespace WebCore { + +InlineIterator BreakingContext::handleEndOfLine() +{ + if (m_lineBreak == m_resolver.position() && (!m_lineBreak.object() || !m_lineBreak.object()->isBR())) { + // we just add as much as possible + if (m_blockStyle->whiteSpace() == PRE && !m_current.offset()) { + m_lineBreak.moveTo(m_lastObject, m_lastObject->isText() ? m_lastObject->length() : 0); + } else if (m_lineBreak.object()) { + // Don't ever break in the middle of a word if we can help it. + // There's no room at all. We just have to be on this line, + // even though we'll spill out. + m_lineBreak.moveTo(m_current.object(), m_current.offset()); + } + } + + // FIXME Bug 100049: We do not need to consume input in a multi-segment line + // unless no segment will. + if (m_lineBreak == m_resolver.position()) + m_lineBreak.increment(); + + // Sanity check our midpoints. + m_lineMidpointState.checkMidpoints(m_lineBreak); + + m_trailingObjects.updateMidpointsForTrailingObjects(m_lineMidpointState, m_lineBreak, TrailingObjects::CollapseFirstSpace); + + // We might have made lineBreak an iterator that points past the end + // of the object. Do this adjustment to make it point to the start + // of the next object instead to avoid confusing the rest of the + // code. + if (m_lineBreak.offset()) { + // This loop enforces the invariant that line breaks should never point + // at an empty inline. See http://crbug.com/305904. + do { + m_lineBreak.setOffset(m_lineBreak.offset() - 1); + m_lineBreak.increment(); + } while (!m_lineBreak.atEnd() && isEmptyInline(m_lineBreak.object())); + } + + return m_lineBreak; +} + +} diff --git a/chromium/third_party/WebKit/Source/core/rendering/line/BreakingContextInlineHeaders.h b/chromium/third_party/WebKit/Source/core/rendering/line/BreakingContextInlineHeaders.h index 989d7e3cfd0..fba56c6fa7c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/line/BreakingContextInlineHeaders.h +++ b/chromium/third_party/WebKit/Source/core/rendering/line/BreakingContextInlineHeaders.h @@ -26,183 +26,25 @@ #include "core/rendering/InlineIterator.h" #include "core/rendering/InlineTextBox.h" -#include "core/rendering/LineWidth.h" #include "core/rendering/RenderCombineText.h" #include "core/rendering/RenderInline.h" +#include "core/rendering/RenderLayer.h" +#include "core/rendering/RenderListMarker.h" +#include "core/rendering/RenderRubyRun.h" #include "core/rendering/break_lines.h" +#include "core/rendering/line/LineBreaker.h" #include "core/rendering/line/LineInfo.h" -#include "core/rendering/shapes/ShapeInsideInfo.h" +#include "core/rendering/line/LineWidth.h" +#include "core/rendering/line/RenderTextInfo.h" +#include "core/rendering/line/TrailingObjects.h" +#include "core/rendering/line/WordMeasurement.h" #include "core/rendering/svg/RenderSVGInlineText.h" namespace WebCore { -using namespace std; -using namespace WTF; -using namespace Unicode; - // We don't let our line box tree for a single line get any deeper than this. const unsigned cMaxLineDepth = 200; -struct RenderTextInfo { - // Destruction of m_layout requires TextLayout to be a complete type, so the constructor and destructor are made non-inline to avoid compilation errors. - RenderTextInfo(); - ~RenderTextInfo(); - - RenderText* m_text; - OwnPtr<TextLayout> m_layout; - LazyLineBreakIterator m_lineBreakIterator; - const Font* m_font; - - void createLayout(RenderText* renderText, float xPos, bool collapseWhiteSpace) - { -#if OS(MACOSX) - m_layout = m_font->createLayoutForMacComplexText(RenderBlockFlow::constructTextRun(renderText, *m_font, renderText, renderText->style()), renderText->textLength(), xPos, collapseWhiteSpace); -#else - m_layout = nullptr; -#endif - } -}; - -class WordMeasurement { -public: - WordMeasurement() - : renderer(0) - , width(0) - , startOffset(0) - , endOffset(0) - { - } - - RenderText* renderer; - float width; - int startOffset; - int endOffset; - HashSet<const SimpleFontData*> fallbackFonts; -}; - -// Don't call this directly. Use one of the descriptive helper functions below. -inline void deprecatedAddMidpoint(LineMidpointState& lineMidpointState, const InlineIterator& midpoint) -{ - if (lineMidpointState.midpoints.size() <= lineMidpointState.numMidpoints) - lineMidpointState.midpoints.grow(lineMidpointState.numMidpoints + 10); - - InlineIterator* midpoints = lineMidpointState.midpoints.data(); - midpoints[lineMidpointState.numMidpoints++] = midpoint; -} - -inline void startIgnoringSpaces(LineMidpointState& lineMidpointState, const InlineIterator& midpoint) -{ - ASSERT(!(lineMidpointState.numMidpoints % 2)); - deprecatedAddMidpoint(lineMidpointState, midpoint); -} - -inline void stopIgnoringSpaces(LineMidpointState& lineMidpointState, const InlineIterator& midpoint) -{ - ASSERT(lineMidpointState.numMidpoints % 2); - deprecatedAddMidpoint(lineMidpointState, midpoint); -} - -// When ignoring spaces, this needs to be called for objects that need line boxes such as RenderInlines or -// hard line breaks to ensure that they're not ignored. -inline void ensureLineBoxInsideIgnoredSpaces(LineMidpointState& lineMidpointState, RenderObject* renderer) -{ - InlineIterator midpoint(0, renderer, 0); - stopIgnoringSpaces(lineMidpointState, midpoint); - startIgnoringSpaces(lineMidpointState, midpoint); -} - -// Adding a pair of midpoints before a character will split it out into a new line box. -inline void ensureCharacterGetsLineBox(LineMidpointState& lineMidpointState, InlineIterator& textParagraphSeparator) -{ - InlineIterator midpoint(0, textParagraphSeparator.object(), textParagraphSeparator.m_pos); - startIgnoringSpaces(lineMidpointState, InlineIterator(0, textParagraphSeparator.object(), textParagraphSeparator.m_pos - 1)); - stopIgnoringSpaces(lineMidpointState, InlineIterator(0, textParagraphSeparator.object(), textParagraphSeparator.m_pos)); -} - -class TrailingObjects { -public: - TrailingObjects(); - void setTrailingWhitespace(RenderText*); - void clear(); - void appendBoxIfNeeded(RenderBox*); - - enum CollapseFirstSpaceOrNot { DoNotCollapseFirstSpace, CollapseFirstSpace }; - - void updateMidpointsForTrailingBoxes(LineMidpointState&, const InlineIterator& lBreak, CollapseFirstSpaceOrNot); - -private: - RenderText* m_whitespace; - Vector<RenderBox*, 4> m_boxes; -}; - -TrailingObjects::TrailingObjects() - : m_whitespace(0) -{ -} - -inline void TrailingObjects::setTrailingWhitespace(RenderText* whitespace) -{ - ASSERT(whitespace); - m_whitespace = whitespace; -} - -inline void TrailingObjects::clear() -{ - m_whitespace = 0; - // Using resize(0) rather than clear() here saves 2% on - // PerformanceTests/Layout/line-layout.html because we avoid freeing and - // re-allocating the underlying buffer repeatedly. - m_boxes.resize(0); -} - -inline void TrailingObjects::appendBoxIfNeeded(RenderBox* box) -{ - if (m_whitespace) - m_boxes.append(box); -} - -void TrailingObjects::updateMidpointsForTrailingBoxes(LineMidpointState& lineMidpointState, const InlineIterator& lBreak, CollapseFirstSpaceOrNot collapseFirstSpace) -{ - if (!m_whitespace) - return; - - // This object is either going to be part of the last midpoint, or it is going to be the actual endpoint. - // In both cases we just decrease our pos by 1 level to exclude the space, allowing it to - in effect - collapse into the newline. - if (lineMidpointState.numMidpoints % 2) { - // Find the trailing space object's midpoint. - int trailingSpaceMidpoint = lineMidpointState.numMidpoints - 1; - for ( ; trailingSpaceMidpoint > 0 && lineMidpointState.midpoints[trailingSpaceMidpoint].object() != m_whitespace; --trailingSpaceMidpoint) { } - ASSERT(trailingSpaceMidpoint >= 0); - if (collapseFirstSpace == CollapseFirstSpace) - lineMidpointState.midpoints[trailingSpaceMidpoint].m_pos--; - - // Now make sure every single trailingPositionedBox following the trailingSpaceMidpoint properly stops and starts - // ignoring spaces. - size_t currentMidpoint = trailingSpaceMidpoint + 1; - for (size_t i = 0; i < m_boxes.size(); ++i) { - if (currentMidpoint >= lineMidpointState.numMidpoints) { - // We don't have a midpoint for this box yet. - ensureLineBoxInsideIgnoredSpaces(lineMidpointState, m_boxes[i]); - } else { - ASSERT(lineMidpointState.midpoints[currentMidpoint].object() == m_boxes[i]); - ASSERT(lineMidpointState.midpoints[currentMidpoint + 1].object() == m_boxes[i]); - } - currentMidpoint += 2; - } - } else if (!lBreak.object()) { - ASSERT(m_whitespace->isText()); - ASSERT(collapseFirstSpace == CollapseFirstSpace); - // Add a new end midpoint that stops right at the very end. - unsigned length = m_whitespace->textLength(); - unsigned pos = length >= 2 ? length - 2 : UINT_MAX; - InlineIterator endMid(0, m_whitespace, pos); - startIgnoringSpaces(lineMidpointState, endMid); - for (size_t i = 0; i < m_boxes.size(); ++i) { - ensureLineBoxInsideIgnoredSpaces(lineMidpointState, m_boxes[i]); - } - } -} - class BreakingContext { public: BreakingContext(InlineBidiResolver& resolver, LineInfo& inLineInfo, LineWidth& lineWidth, RenderTextInfo& inRenderTextInfo, FloatingObject* inLastFloatFromPreviousLine, bool appliedStartWidth, RenderBlockFlow* block) @@ -309,8 +151,6 @@ private: TrailingObjects m_trailingObjects; }; -enum WhitespacePosition { LeadingWhitespace, TrailingWhitespace }; - inline bool shouldCollapseWhiteSpace(const RenderStyle* style, const LineInfo& lineInfo, WhitespacePosition whitespacePosition) { // CSS2 16.6.1 @@ -441,7 +281,7 @@ inline void BreakingContext::handleBR(EClear& clear) // need to check for floats to clear - so if we're ignoring spaces, stop ignoring them and add a // run for this object. if (m_ignoringSpaces && m_currentStyle->clear() != CNONE) - ensureLineBoxInsideIgnoredSpaces(m_lineMidpointState, br); + m_lineMidpointState.ensureLineBoxInsideIgnoredSpaces(br); if (!m_lineInfo.isEmpty()) clear = m_currentStyle->clear(); @@ -495,7 +335,7 @@ inline void BreakingContext::handleOutOfFlowPositioned(Vector<RenderBox*>& posit RenderBox* box = toRenderBox(m_current.object()); bool isInlineType = box->style()->isOriginalDisplayInlineType(); if (!isInlineType) { - m_block->setStaticInlinePositionForChild(box, m_block->logicalHeight(), m_block->startOffsetForContent(m_block->logicalHeight())); + m_block->setStaticInlinePositionForChild(box, m_block->logicalHeight(), m_block->startOffsetForContent()); } else { // If our original display was an INLINE type, then we can go ahead // and determine our static y position now. @@ -506,12 +346,12 @@ inline void BreakingContext::handleOutOfFlowPositioned(Vector<RenderBox*>& posit // then start ignoring spaces again. if (isInlineType || box->container()->isRenderInline()) { if (m_ignoringSpaces) - ensureLineBoxInsideIgnoredSpaces(m_lineMidpointState, box); - m_trailingObjects.appendBoxIfNeeded(box); + m_lineMidpointState.ensureLineBoxInsideIgnoredSpaces(box); + m_trailingObjects.appendObjectIfNeeded(box); } else { positionedObjects.append(box); } - m_width.addUncommittedWidth(inlineLogicalWidth(box)); + m_width.addUncommittedWidth(inlineLogicalWidth(box).toFloat()); // Reset prior line break context characters. m_renderTextInfo.m_lineBreakIterator.resetPriorContext(); } @@ -524,10 +364,10 @@ inline void BreakingContext::handleFloat() // If it does, position it now, otherwise, position // it after moving to next line (in newLine() func) // FIXME: Bug 110372: Properly position multiple stacked floats with non-rectangular shape outside. - if (m_floatsFitOnLine && m_width.fitsOnLine(m_block->logicalWidthForFloat(floatingObject))) { + if (m_floatsFitOnLine && m_width.fitsOnLine(m_block->logicalWidthForFloat(floatingObject).toFloat(), ExcludeWhitespace)) { m_block->positionNewFloatOnLine(floatingObject, m_lastFloatFromPreviousLine, m_lineInfo, m_width); if (m_lineBreak.object() == m_current.object()) { - ASSERT(!m_lineBreak.m_pos); + ASSERT(!m_lineBreak.offset()); m_lineBreak.increment(); } } else { @@ -549,7 +389,7 @@ inline bool shouldSkipWhitespaceAfterStartObject(RenderBlockFlow* block, RenderO RenderText* nextText = toRenderText(next); UChar nextChar = nextText->characterAt(0); if (nextText->style()->isCollapsibleWhiteSpace(nextChar)) { - startIgnoringSpaces(lineMidpointState, InlineIterator(0, o, 0)); + lineMidpointState.startIgnoringSpaces(InlineIterator(0, o, 0)); return true; } } @@ -564,29 +404,31 @@ inline void BreakingContext::handleEmptyInline() RenderInline* flowBox = toRenderInline(m_current.object()); - // Now that some inline flows have line boxes, if we are already ignoring spaces, we need - // to make sure that we stop to include this object and then start ignoring spaces again. - // If this object is at the start of the line, we need to behave like list markers and - // start ignoring spaces. bool requiresLineBox = alwaysRequiresLineBox(m_current.object()); if (requiresLineBox || requiresLineBoxForContent(flowBox, m_lineInfo)) { - // An empty inline that only has line-height, vertical-align or font-metrics will only get a - // line box to affect the height of the line if the rest of the line is not empty. + // An empty inline that only has line-height, vertical-align or font-metrics will + // not force linebox creation (and thus affect the height of the line) if the rest of the line is empty. if (requiresLineBox) m_lineInfo.setEmpty(false, m_block, &m_width); if (m_ignoringSpaces) { + // If we are in a run of ignored spaces then ensure we get a linebox if lineboxes are eventually + // created for the line... m_trailingObjects.clear(); - ensureLineBoxInsideIgnoredSpaces(m_lineMidpointState, m_current.object()); + m_lineMidpointState.ensureLineBoxInsideIgnoredSpaces(m_current.object()); } else if (m_blockStyle->collapseWhiteSpace() && m_resolver.position().object() == m_current.object() && shouldSkipWhitespaceAfterStartObject(m_block, m_current.object(), m_lineMidpointState)) { - // Like with list markers, we start ignoring spaces to make sure that any - // additional spaces we see will be discarded. + // If this object is at the start of the line, we need to behave like list markers and + // start ignoring spaces. m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = true; m_ignoringSpaces = true; + } else { + // If we are after a trailing space but aren't ignoring spaces yet then ensure we get a linebox + // if we encounter collapsible whitepace. + m_trailingObjects.appendObjectIfNeeded(m_current.object()); } } - m_width.addUncommittedWidth(inlineLogicalWidth(m_current.object()) + borderPaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox)); + m_width.addUncommittedWidth((inlineLogicalWidth(m_current.object()) + borderPaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox)).toFloat()); } inline void BreakingContext::handleReplaced() @@ -603,7 +445,7 @@ inline void BreakingContext::handleReplaced() } if (m_ignoringSpaces) - stopIgnoringSpaces(m_lineMidpointState, InlineIterator(0, m_current.object(), 0)); + m_lineMidpointState.stopIgnoringSpaces(InlineIterator(0, m_current.object(), 0)); m_lineInfo.setEmpty(false, m_block, &m_width); m_ignoringSpaces = false; @@ -621,9 +463,9 @@ inline void BreakingContext::handleReplaced() m_ignoringSpaces = true; } if (toRenderListMarker(m_current.object())->isInside()) - m_width.addUncommittedWidth(replacedLogicalWidth); + m_width.addUncommittedWidth(replacedLogicalWidth.toFloat()); } else { - m_width.addUncommittedWidth(replacedLogicalWidth); + m_width.addUncommittedWidth(replacedLogicalWidth.toFloat()); } if (m_current.object()->isRubyRun()) m_width.applyOverhang(toRenderRubyRun(m_current.object()), m_lastObject, m_nextObject); @@ -633,7 +475,7 @@ inline void BreakingContext::handleReplaced() inline bool iteratorIsBeyondEndOfRenderCombineText(const InlineIterator& iter, RenderCombineText* renderer) { - return iter.object() == renderer && iter.m_pos >= renderer->textLength(); + return iter.object() == renderer && iter.offset() >= renderer->textLength(); } inline void nextCharacter(UChar& currentCharacter, UChar& lastCharacter, UChar& secondToLastCharacter) @@ -651,66 +493,26 @@ inline float firstPositiveWidth(const WordMeasurements& wordMeasurements) return 0; } -inline void updateSegmentsForShapes(RenderBlockFlow* block, const FloatingObject* lastFloatFromPreviousLine, const WordMeasurements& wordMeasurements, LineWidth& width, bool isFirstLine) +inline float measureHyphenWidth(RenderText* renderer, const Font& font, TextDirection textDirection) { - ASSERT(lastFloatFromPreviousLine); - - ShapeInsideInfo* shapeInsideInfo = block->layoutShapeInsideInfo(); - if (!lastFloatFromPreviousLine->isPlaced() || !shapeInsideInfo) - return; - - bool isHorizontalWritingMode = block->isHorizontalWritingMode(); - LayoutUnit logicalOffsetFromShapeContainer = block->logicalOffsetFromShapeAncestorContainer(shapeInsideInfo->owner()).height(); - - LayoutUnit lineLogicalTop = block->logicalHeight() + logicalOffsetFromShapeContainer; - LayoutUnit lineLogicalHeight = block->lineHeight(isFirstLine, isHorizontalWritingMode ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); - LayoutUnit lineLogicalBottom = lineLogicalTop + lineLogicalHeight; - - LayoutUnit floatLogicalTop = block->logicalTopForFloat(lastFloatFromPreviousLine); - LayoutUnit floatLogicalBottom = block->logicalBottomForFloat(lastFloatFromPreviousLine); - - bool lineOverlapsWithFloat = (floatLogicalTop < lineLogicalBottom) && (lineLogicalTop < floatLogicalBottom); - if (!lineOverlapsWithFloat) - return; - - float minSegmentWidth = firstPositiveWidth(wordMeasurements); - - LayoutUnit floatLogicalWidth = block->logicalWidthForFloat(lastFloatFromPreviousLine); - LayoutUnit availableLogicalWidth = block->logicalWidth() - block->logicalRightForFloat(lastFloatFromPreviousLine); - if (availableLogicalWidth < minSegmentWidth) - block->setLogicalHeight(floatLogicalBottom); - - if (block->logicalHeight() < floatLogicalTop) { - shapeInsideInfo->adjustLogicalLineTop(minSegmentWidth + floatLogicalWidth); - block->setLogicalHeight(shapeInsideInfo->logicalLineTop() - logicalOffsetFromShapeContainer); - } - - lineLogicalTop = block->logicalHeight() + logicalOffsetFromShapeContainer; - - shapeInsideInfo->updateSegmentsForLine(lineLogicalTop, lineLogicalHeight); - width.updateCurrentShapeSegment(); - width.updateAvailableWidth(); + RenderStyle* style = renderer->style(); + return font.width(RenderBlockFlow::constructTextRun(renderer, font, + style->hyphenString().string(), style, style->direction())); } -inline float measureHyphenWidth(RenderText* renderer, const Font& font) +ALWAYS_INLINE TextDirection textDirectionFromUnicode(WTF::Unicode::Direction direction) { - RenderStyle* style = renderer->style(); - return font.width(RenderBlockFlow::constructTextRun(renderer, font, style->hyphenString().string(), style)); + return direction == WTF::Unicode::RightToLeft + || direction == WTF::Unicode::RightToLeftArabic ? RTL : LTR; } -ALWAYS_INLINE float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace, HashSet<const SimpleFontData*>* fallbackFonts = 0, TextLayout* layout = 0) +ALWAYS_INLINE float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace, HashSet<const SimpleFontData*>* fallbackFonts = 0) { GlyphOverflow glyphOverflow; if (isFixedPitch || (!from && len == text->textLength()) || text->style()->hasTextCombine()) - return text->width(from, len, font, xPos, fallbackFonts, &glyphOverflow); - - if (layout) - return Font::width(*layout, from, len, fallbackFonts); + return text->width(from, len, font, xPos, text->style()->direction(), fallbackFonts, &glyphOverflow); TextRun run = RenderBlockFlow::constructTextRun(text, font, text, from, len, text->style()); - run.setCharactersLength(text->textLength() - from); - ASSERT(run.charactersLength() >= run.length()); - run.setCharacterScanForCodePath(!text->canUseSimpleFontCodePath()); run.setTabSize(!collapseWhiteSpace, text->style()->tabSize()); run.setXPos(xPos); @@ -719,13 +521,20 @@ ALWAYS_INLINE float textWidth(RenderText* text, unsigned from, unsigned len, con inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool& hyphenated) { - if (!m_current.m_pos) + if (!m_current.offset()) m_appliedStartWidth = false; RenderText* renderText = toRenderText(m_current.object()); bool isSVGText = renderText->isSVGInlineText(); + // If we have left a no-wrap inline and entered an autowrap inline while ignoring spaces + // then we need to mark the start of the autowrap inline as a potential linebreak now. + if (m_autoWrap && !RenderStyle::autoWrap(m_lastWS) && m_ignoringSpaces) { + m_width.commit(); + m_lineBreak.moveToStartOf(m_current.object()); + } + if (renderText->style()->hasTextCombine() && m_current.object()->isCombineText() && !toRenderCombineText(m_current.object())->isCombined()) { RenderCombineText* combineRenderer = toRenderCombineText(m_current.object()); combineRenderer->combineText(); @@ -741,7 +550,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool const Font& font = style->font(); bool isFixedPitch = font.isFixedPitch(); - unsigned lastSpace = m_current.m_pos; + unsigned lastSpace = m_current.offset(); float wordSpacing = m_currentStyle->wordSpacing(); float lastSpaceWordSpacing = 0; float wordSpacingForWordMeasurement = 0; @@ -763,28 +572,28 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool if (renderText->isWordBreak()) { m_width.commit(); m_lineBreak.moveToStartOf(m_current.object()); - ASSERT(m_current.m_pos == renderText->textLength()); + ASSERT(m_current.offset() == renderText->textLength()); } if (m_renderTextInfo.m_text != renderText) { m_renderTextInfo.m_text = renderText; m_renderTextInfo.m_font = &font; - m_renderTextInfo.createLayout(renderText, m_width.currentWidth(), m_collapseWhiteSpace); m_renderTextInfo.m_lineBreakIterator.resetStringAndReleaseIterator(renderText->text(), style->locale()); - } else if (m_renderTextInfo.m_layout && m_renderTextInfo.m_font != &font) { + } else if (m_renderTextInfo.m_font != &font) { m_renderTextInfo.m_font = &font; - m_renderTextInfo.createLayout(renderText, m_width.currentWidth(), m_collapseWhiteSpace); } - TextLayout* textLayout = m_renderTextInfo.m_layout.get(); - - // Non-zero only when kerning is enabled and TextLayout isn't used, in which case we measure + // Non-zero only when kerning is enabled, in which case we measure // words with their trailing space, then subtract its width. - float wordTrailingSpaceWidth = (font.typesettingFeatures() & Kerning) && !textLayout ? font.width(RenderBlockFlow::constructTextRun(renderText, font, &space, 1, style)) + wordSpacing : 0; + float wordTrailingSpaceWidth = (font.fontDescription().typesettingFeatures() & Kerning) ? + font.width(RenderBlockFlow::constructTextRun( + renderText, font, &space, 1, style, + style->direction())) + wordSpacing + : 0; UChar lastCharacter = m_renderTextInfo.m_lineBreakIterator.lastCharacter(); UChar secondToLastCharacter = m_renderTextInfo.m_lineBreakIterator.secondToLastCharacter(); - for (; m_current.m_pos < renderText->textLength(); m_current.fastIncrementInTextNode()) { + for (; m_current.offset() < renderText->textLength(); m_current.fastIncrementInTextNode()) { bool previousCharacterIsSpace = m_currentCharacterIsSpace; bool previousCharacterShouldCollapseIfPreWap = m_currentCharacterShouldCollapseIfPreWap; UChar c = m_current.current(); @@ -794,7 +603,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool m_lineInfo.setEmpty(false, m_block, &m_width); if (c == softHyphen && m_autoWrap && !hyphenWidth) { - hyphenWidth = measureHyphenWidth(renderText, font); + hyphenWidth = measureHyphenWidth(renderText, font, textDirectionFromUnicode(m_resolver.position().direction())); m_width.addUncommittedWidth(hyphenWidth); } @@ -802,12 +611,14 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool if ((breakAll || breakWords) && !midWordBreak) { wrapW += charWidth; - bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && m_current.m_pos + 1 < renderText->textLength() && U16_IS_TRAIL((*renderText)[m_current.m_pos + 1]); - charWidth = textWidth(renderText, m_current.m_pos, midWordBreakIsBeforeSurrogatePair ? 2 : 1, font, m_width.committedWidth() + wrapW, isFixedPitch, m_collapseWhiteSpace, 0, textLayout); + bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && m_current.offset() + 1 < renderText->textLength() && U16_IS_TRAIL((*renderText)[m_current.offset() + 1]); + charWidth = textWidth(renderText, m_current.offset(), midWordBreakIsBeforeSurrogatePair ? 2 : 1, font, m_width.committedWidth() + wrapW, isFixedPitch, m_collapseWhiteSpace, 0); midWordBreak = m_width.committedWidth() + wrapW + charWidth > m_width.availableWidth(); } - bool betweenWords = c == '\n' || (m_currWS != PRE && !m_atStart && isBreakable(m_renderTextInfo.m_lineBreakIterator, m_current.m_pos, m_current.m_nextBreakablePosition)); + int nextBreakablePosition = m_current.nextBreakablePosition(); + bool betweenWords = c == '\n' || (m_currWS != PRE && !m_atStart && isBreakable(m_renderTextInfo.m_lineBreakIterator, m_current.offset(), nextBreakablePosition)); + m_current.setNextBreakablePosition(nextBreakablePosition); if (betweenWords || midWordBreak) { bool stoppedIgnoringSpaces = false; @@ -818,8 +629,8 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool // new point. m_ignoringSpaces = false; wordSpacingForWordMeasurement = 0; - lastSpace = m_current.m_pos; // e.g., "Foo goo", don't add in any of the ignored spaces. - stopIgnoringSpaces(m_lineMidpointState, InlineIterator(0, m_current.object(), m_current.m_pos)); + lastSpace = m_current.offset(); // e.g., "Foo goo", don't add in any of the ignored spaces. + m_lineMidpointState.stopIgnoringSpaces(InlineIterator(0, m_current.object(), m_current.offset())); stoppedIgnoringSpaces = true; } else { // Just keep ignoring these spaces. @@ -832,37 +643,38 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool WordMeasurement& wordMeasurement = wordMeasurements.last(); wordMeasurement.renderer = renderText; - wordMeasurement.endOffset = m_current.m_pos; + wordMeasurement.endOffset = m_current.offset(); wordMeasurement.startOffset = lastSpace; - float additionalTmpW; + float additionalTempWidth; if (wordTrailingSpaceWidth && c == ' ') - additionalTmpW = textWidth(renderText, lastSpace, m_current.m_pos + 1 - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout) - wordTrailingSpaceWidth; + additionalTempWidth = textWidth(renderText, lastSpace, m_current.offset() + 1 - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts) - wordTrailingSpaceWidth; else - additionalTmpW = textWidth(renderText, lastSpace, m_current.m_pos - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout); + additionalTempWidth = textWidth(renderText, lastSpace, m_current.offset() - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts); + + wordMeasurement.width = additionalTempWidth + wordSpacingForWordMeasurement; + additionalTempWidth += lastSpaceWordSpacing; + m_width.addUncommittedWidth(additionalTempWidth); + + if (m_collapseWhiteSpace && previousCharacterIsSpace && m_currentCharacterIsSpace && additionalTempWidth) + m_width.setTrailingWhitespaceWidth(additionalTempWidth); - wordMeasurement.width = additionalTmpW + wordSpacingForWordMeasurement; - additionalTmpW += lastSpaceWordSpacing; - m_width.addUncommittedWidth(additionalTmpW); if (!m_appliedStartWidth) { - m_width.addUncommittedWidth(inlineLogicalWidth(m_current.object(), true, false)); + m_width.addUncommittedWidth(inlineLogicalWidth(m_current.object(), true, false).toFloat()); m_appliedStartWidth = true; } - if (m_lastFloatFromPreviousLine) - updateSegmentsForShapes(m_block, m_lastFloatFromPreviousLine, wordMeasurements, m_width, m_lineInfo.isFirstLine()); - applyWordSpacing = wordSpacing && m_currentCharacterIsSpace; if (!m_width.committedWidth() && m_autoWrap && !m_width.fitsOnLine()) - m_width.fitBelowFloats(); + m_width.fitBelowFloats(m_lineInfo.isFirstLine()); if (m_autoWrap || breakWords) { // If we break only after white-space, consider the current character // as candidate width for this line. bool lineWasTooWide = false; if (m_width.fitsOnLine() && m_currentCharacterIsSpace && m_currentStyle->breakOnlyAfterWhiteSpace() && !midWordBreak) { - float charWidth = textWidth(renderText, m_current.m_pos, 1, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout) + (applyWordSpacing ? wordSpacing : 0); + float charWidth = textWidth(renderText, m_current.offset(), 1, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts) + (applyWordSpacing ? wordSpacing : 0); // Check if line is too big even without the extra space // at the end of the line. If it is not, do nothing. // If the line needs the extra whitespace to be too long, @@ -870,23 +682,23 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool // additional whitespace. if (!m_width.fitsOnLine(charWidth)) { lineWasTooWide = true; - m_lineBreak.moveTo(m_current.object(), m_current.m_pos, m_current.m_nextBreakablePosition); + m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition()); skipTrailingWhitespace(m_lineBreak, m_lineInfo); } } if (lineWasTooWide || !m_width.fitsOnLine()) { if (m_lineBreak.atTextParagraphSeparator()) { - if (!stoppedIgnoringSpaces && m_current.m_pos > 0) - ensureCharacterGetsLineBox(m_lineMidpointState, m_current); + if (!stoppedIgnoringSpaces && m_current.offset() > 0) + m_lineMidpointState.ensureCharacterGetsLineBox(m_current); m_lineBreak.increment(); m_lineInfo.setPreviousLineBrokeCleanly(true); - wordMeasurement.endOffset = m_lineBreak.m_pos; + wordMeasurement.endOffset = m_lineBreak.offset(); } - if (m_lineBreak.object() && m_lineBreak.m_pos && m_lineBreak.object()->isText() && toRenderText(m_lineBreak.object())->textLength() && toRenderText(m_lineBreak.object())->characterAt(m_lineBreak.m_pos - 1) == softHyphen) + if (m_lineBreak.object() && m_lineBreak.offset() && m_lineBreak.object()->isText() && toRenderText(m_lineBreak.object())->textLength() && toRenderText(m_lineBreak.object())->characterAt(m_lineBreak.offset() - 1) == softHyphen) hyphenated = true; - if (m_lineBreak.m_pos && m_lineBreak.m_pos != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) { + if (m_lineBreak.offset() && m_lineBreak.offset() != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) { if (charWidth) { - wordMeasurement.endOffset = m_lineBreak.m_pos; + wordMeasurement.endOffset = m_lineBreak.offset(); wordMeasurement.width = charWidth; } } @@ -897,7 +709,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool } } else { if (!betweenWords || (midWordBreak && !m_autoWrap)) - m_width.addUncommittedWidth(-additionalTmpW); + m_width.addUncommittedWidth(-additionalTempWidth); if (hyphenWidth) { // Subtract the width of the soft hyphen out since we fit on a line. m_width.addUncommittedWidth(-hyphenWidth); @@ -907,9 +719,9 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool } if (c == '\n' && m_preservesNewline) { - if (!stoppedIgnoringSpaces && m_current.m_pos > 0) - ensureCharacterGetsLineBox(m_lineMidpointState, m_current); - m_lineBreak.moveTo(m_current.object(), m_current.m_pos, m_current.m_nextBreakablePosition); + if (!stoppedIgnoringSpaces && m_current.offset()) + m_lineMidpointState.ensureCharacterGetsLineBox(m_current); + m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition()); m_lineBreak.increment(); m_lineInfo.setPreviousLineBrokeCleanly(true); return true; @@ -918,23 +730,23 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool if (m_autoWrap && betweenWords) { m_width.commit(); wrapW = 0; - m_lineBreak.moveTo(m_current.object(), m_current.m_pos, m_current.m_nextBreakablePosition); + m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition()); // Auto-wrapping text should not wrap in the middle of a word once it has had an // opportunity to break after a word. breakWords = false; } - if (midWordBreak && !U16_IS_TRAIL(c) && !(category(c) & (Mark_NonSpacing | Mark_Enclosing | Mark_SpacingCombining))) { + if (midWordBreak && !U16_IS_TRAIL(c) && !(WTF::Unicode::category(c) & (WTF::Unicode::Mark_NonSpacing | WTF::Unicode::Mark_Enclosing | WTF::Unicode::Mark_SpacingCombining))) { // Remember this as a breakable position in case // adding the end width forces a break. - m_lineBreak.moveTo(m_current.object(), m_current.m_pos, m_current.m_nextBreakablePosition); + m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition()); midWordBreak &= (breakWords || breakAll); } if (betweenWords) { lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0; wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurement.width) ? wordSpacing : 0; - lastSpace = m_current.m_pos; + lastSpace = m_current.offset(); } if (!m_ignoringSpaces && m_currentStyle->collapseWhiteSpace()) { @@ -947,8 +759,8 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool // We just entered a mode where we are ignoring // spaces. Create a midpoint to terminate the run // before the second space. - startIgnoringSpaces(m_lineMidpointState, m_startOfIgnoredSpaces); - m_trailingObjects.updateMidpointsForTrailingBoxes(m_lineMidpointState, InlineIterator(), TrailingObjects::DoNotCollapseFirstSpace); + m_lineMidpointState.startIgnoringSpaces(m_startOfIgnoredSpaces); + m_trailingObjects.updateMidpointsForTrailingObjects(m_lineMidpointState, InlineIterator(), TrailingObjects::DoNotCollapseFirstSpace); } } } else if (m_ignoringSpaces) { @@ -957,24 +769,24 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool m_ignoringSpaces = false; lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0; wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurements.last().width) ? wordSpacing : 0; - lastSpace = m_current.m_pos; // e.g., "Foo goo", don't add in any of the ignored spaces. - stopIgnoringSpaces(m_lineMidpointState, InlineIterator(0, m_current.object(), m_current.m_pos)); + lastSpace = m_current.offset(); // e.g., "Foo goo", don't add in any of the ignored spaces. + m_lineMidpointState.stopIgnoringSpaces(InlineIterator(0, m_current.object(), m_current.offset())); } - if (isSVGText && m_current.m_pos > 0) { + if (isSVGText && m_current.offset()) { // Force creation of new InlineBoxes for each absolute positioned character (those that start new text chunks). - if (toRenderSVGInlineText(renderText)->characterStartsNewTextChunk(m_current.m_pos)) - ensureCharacterGetsLineBox(m_lineMidpointState, m_current); + if (toRenderSVGInlineText(renderText)->characterStartsNewTextChunk(m_current.offset())) + m_lineMidpointState.ensureCharacterGetsLineBox(m_current); } if (m_currentCharacterIsSpace && !previousCharacterIsSpace) { m_startOfIgnoredSpaces.setObject(m_current.object()); - m_startOfIgnoredSpaces.m_pos = m_current.m_pos; + m_startOfIgnoredSpaces.setOffset(m_current.offset()); } if (!m_currentCharacterIsSpace && previousCharacterShouldCollapseIfPreWap) { if (m_autoWrap && m_currentStyle->breakOnlyAfterWhiteSpace()) - m_lineBreak.moveTo(m_current.object(), m_current.m_pos, m_current.m_nextBreakablePosition); + m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition()); } if (m_collapseWhiteSpace && m_currentCharacterIsSpace && !m_ignoringSpaces) @@ -993,12 +805,18 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool wordMeasurement.renderer = renderText; // IMPORTANT: current.m_pos is > length here! - float additionalTmpW = m_ignoringSpaces ? 0 : textWidth(renderText, lastSpace, m_current.m_pos - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout); + float additionalTempWidth = m_ignoringSpaces ? 0 : textWidth(renderText, lastSpace, m_current.offset() - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts); wordMeasurement.startOffset = lastSpace; - wordMeasurement.endOffset = m_current.m_pos; - wordMeasurement.width = m_ignoringSpaces ? 0 : additionalTmpW + wordSpacingForWordMeasurement; - additionalTmpW += lastSpaceWordSpacing; - m_width.addUncommittedWidth(additionalTmpW + inlineLogicalWidth(m_current.object(), !m_appliedStartWidth, m_includeEndWidth)); + wordMeasurement.endOffset = m_current.offset(); + wordMeasurement.width = m_ignoringSpaces ? 0 : additionalTempWidth + wordSpacingForWordMeasurement; + additionalTempWidth += lastSpaceWordSpacing; + + LayoutUnit inlineLogicalTempWidth = inlineLogicalWidth(m_current.object(), !m_appliedStartWidth, m_includeEndWidth); + m_width.addUncommittedWidth(additionalTempWidth + inlineLogicalTempWidth); + + if (m_collapseWhiteSpace && m_currentCharacterIsSpace && additionalTempWidth) + m_width.setTrailingWhitespaceWidth(additionalTempWidth + inlineLogicalTempWidth); + m_includeEndWidth = false; if (!m_width.fitsOnLine()) { @@ -1031,7 +849,7 @@ inline void BreakingContext::commitAndUpdateLineBreakIfNeeded() } if (!m_width.fitsOnLine() && !m_width.committedWidth()) - m_width.fitBelowFloats(); + m_width.fitBelowFloats(m_lineInfo.isFirstLine()); bool canPlaceOnLine = m_width.fitsOnLine() || !m_autoWrapWasEverTrueOnLine; if (canPlaceOnLine && checkForBreak) { @@ -1041,6 +859,7 @@ inline void BreakingContext::commitAndUpdateLineBreakIfNeeded() } } + ASSERT_WITH_SECURITY_IMPLICATION(m_currentStyle->refCount() > 0); if (checkForBreak && !m_width.fitsOnLine()) { // if we have floats, try to get below them. if (m_currentCharacterIsSpace && !m_ignoringSpaces && m_currentStyle->collapseWhiteSpace()) @@ -1051,7 +870,7 @@ inline void BreakingContext::commitAndUpdateLineBreakIfNeeded() return; } - m_width.fitBelowFloats(); + m_width.fitBelowFloats(m_lineInfo.isFirstLine()); // |width| may have been adjusted because we got shoved down past a float (thus // giving us more room), so we need to retest, and only jump to @@ -1063,7 +882,7 @@ inline void BreakingContext::commitAndUpdateLineBreakIfNeeded() } else if (m_blockStyle->autoWrap() && !m_width.fitsOnLine() && !m_width.committedWidth()) { // If the container autowraps but the current child does not then we still need to ensure that it // wraps and moves below any floats. - m_width.fitBelowFloats(); + m_width.fitBelowFloats(m_lineInfo.isFirstLine()); } if (!m_current.object()->isFloatingOrOutOfFlowPositioned()) { @@ -1075,69 +894,16 @@ inline void BreakingContext::commitAndUpdateLineBreakIfNeeded() } } -inline void checkMidpoints(LineMidpointState& lineMidpointState, InlineIterator& lBreak) -{ - // Check to see if our last midpoint is a start point beyond the line break. If so, - // shave it off the list, and shave off a trailing space if the previous end point doesn't - // preserve whitespace. - if (lBreak.object() && lineMidpointState.numMidpoints && !(lineMidpointState.numMidpoints % 2)) { - InlineIterator* midpoints = lineMidpointState.midpoints.data(); - InlineIterator& endpoint = midpoints[lineMidpointState.numMidpoints - 2]; - const InlineIterator& startpoint = midpoints[lineMidpointState.numMidpoints - 1]; - InlineIterator currpoint = endpoint; - while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak) - currpoint.increment(); - if (currpoint == lBreak) { - // We hit the line break before the start point. Shave off the start point. - lineMidpointState.numMidpoints--; - if (endpoint.object()->style()->collapseWhiteSpace() && endpoint.object()->isText()) - endpoint.m_pos--; - } - } -} - -InlineIterator BreakingContext::handleEndOfLine() +inline IndentTextOrNot requiresIndent(bool isFirstLine, bool isAfterHardLineBreak, RenderStyle* style) { - ShapeInsideInfo* shapeInfo = m_block->layoutShapeInsideInfo(); - bool segmentAllowsOverflow = !shapeInfo || !shapeInfo->hasSegments(); - - if (m_lineBreak == m_resolver.position() && (!m_lineBreak.object() || !m_lineBreak.object()->isBR()) && segmentAllowsOverflow) { - // we just add as much as possible - if (m_blockStyle->whiteSpace() == PRE && !m_current.m_pos) { - m_lineBreak.moveTo(m_lastObject, m_lastObject->isText() ? m_lastObject->length() : 0); - } else if (m_lineBreak.object()) { - // Don't ever break in the middle of a word if we can help it. - // There's no room at all. We just have to be on this line, - // even though we'll spill out. - m_lineBreak.moveTo(m_current.object(), m_current.m_pos); - } - } + IndentTextOrNot shouldIndentText = DoNotIndentText; + if (isFirstLine || (isAfterHardLineBreak && style->textIndentLine()) == TextIndentEachLine) + shouldIndentText = IndentText; - // FIXME Bug 100049: We do not need to consume input in a multi-segment line - // unless no segment will. - // make sure we consume at least one char/object. - if (m_lineBreak == m_resolver.position() && segmentAllowsOverflow) - m_lineBreak.increment(); - - // Sanity check our midpoints. - checkMidpoints(m_lineMidpointState, m_lineBreak); - - m_trailingObjects.updateMidpointsForTrailingBoxes(m_lineMidpointState, m_lineBreak, TrailingObjects::CollapseFirstSpace); - - // We might have made lineBreak an iterator that points past the end - // of the object. Do this adjustment to make it point to the start - // of the next object instead to avoid confusing the rest of the - // code. - if (m_lineBreak.m_pos > 0) { - // This loop enforces the invariant that line breaks should never point - // at an empty inline. See http://crbug.com/305904. - do { - m_lineBreak.m_pos--; - m_lineBreak.increment(); - } while (!m_lineBreak.atEnd() && isEmptyInline(m_lineBreak.object())); - } + if (style->textIndentType() == TextIndentHanging) + shouldIndentText = shouldIndentText == IndentText ? DoNotIndentText : IndentText; - return m_lineBreak; + return shouldIndentText; } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/line/LineBreaker.cpp b/chromium/third_party/WebKit/Source/core/rendering/line/LineBreaker.cpp new file mode 100644 index 00000000000..074aafe5a4b --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/line/LineBreaker.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved. + * Copyright (C) 2010 Google Inc. 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" +#include "core/rendering/line/LineBreaker.h" + +#include "core/rendering/line/BreakingContextInlineHeaders.h" + +namespace WebCore { + +void LineBreaker::skipLeadingWhitespace(InlineBidiResolver& resolver, LineInfo& lineInfo, + FloatingObject* lastFloatFromPreviousLine, LineWidth& width) +{ + while (!resolver.position().atEnd() && !requiresLineBox(resolver.position(), lineInfo, LeadingWhitespace)) { + RenderObject* object = resolver.position().object(); + if (object->isOutOfFlowPositioned()) { + setStaticPositions(m_block, toRenderBox(object)); + if (object->style()->isOriginalDisplayInlineType()) { + resolver.runs().addRun(createRun(0, 1, object, resolver)); + lineInfo.incrementRunsFromLeadingWhitespace(); + } + } else if (object->isFloating()) { + m_block->positionNewFloatOnLine(m_block->insertFloatingObject(toRenderBox(object)), lastFloatFromPreviousLine, lineInfo, width); + } else if (object->isText() && object->style()->hasTextCombine() && object->isCombineText() && !toRenderCombineText(object)->isCombined()) { + toRenderCombineText(object)->combineText(); + if (toRenderCombineText(object)->isCombined()) + continue; + } + resolver.position().increment(&resolver); + } + resolver.commitExplicitEmbedding(); +} + +void LineBreaker::reset() +{ + m_positionedObjects.clear(); + m_hyphenated = false; + m_clear = CNONE; +} + +InlineIterator LineBreaker::nextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements) +{ + reset(); + + ASSERT(resolver.position().root() == m_block); + + bool appliedStartWidth = resolver.position().offset() > 0; + + LineWidth width(*m_block, lineInfo.isFirstLine(), requiresIndent(lineInfo.isFirstLine(), lineInfo.previousLineBrokeCleanly(), m_block->style())); + + skipLeadingWhitespace(resolver, lineInfo, lastFloatFromPreviousLine, width); + + if (resolver.position().atEnd()) + return resolver.position(); + + BreakingContext context(resolver, lineInfo, width, renderTextInfo, lastFloatFromPreviousLine, appliedStartWidth, m_block); + + while (context.currentObject()) { + context.initializeForCurrentObject(); + if (context.currentObject()->isBR()) { + context.handleBR(m_clear); + } else if (context.currentObject()->isOutOfFlowPositioned()) { + context.handleOutOfFlowPositioned(m_positionedObjects); + } else if (context.currentObject()->isFloating()) { + context.handleFloat(); + } else if (context.currentObject()->isRenderInline()) { + context.handleEmptyInline(); + } else if (context.currentObject()->isReplaced()) { + context.handleReplaced(); + } else if (context.currentObject()->isText()) { + if (context.handleText(wordMeasurements, m_hyphenated)) { + // We've hit a hard text line break. Our line break iterator is updated, so go ahead and early return. + return context.lineBreak(); + } + } else { + ASSERT_NOT_REACHED(); + } + + if (context.atEnd()) + return context.handleEndOfLine(); + + context.commitAndUpdateLineBreakIfNeeded(); + + if (context.atEnd()) + return context.handleEndOfLine(); + + context.increment(); + } + + context.clearLineBreakIfFitsOnLine(); + + return context.handleEndOfLine(); +} + +} diff --git a/chromium/third_party/WebKit/Source/core/rendering/line/LineBreaker.h b/chromium/third_party/WebKit/Source/core/rendering/line/LineBreaker.h new file mode 100644 index 00000000000..2cb519205df --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/line/LineBreaker.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved. + * Copyright (C) 2010 Google Inc. 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 LineBreaker_h +#define LineBreaker_h + +#include "core/rendering/InlineIterator.h" +#include "core/rendering/line/LineInfo.h" +#include "wtf/Vector.h" + +namespace WebCore { + +enum WhitespacePosition { LeadingWhitespace, TrailingWhitespace }; + +struct RenderTextInfo; + +class LineBreaker { +public: + friend class BreakingContext; + LineBreaker(RenderBlockFlow* block) + : m_block(block) + { + reset(); + } + + InlineIterator nextLineBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&); + + bool lineWasHyphenated() { return m_hyphenated; } + const Vector<RenderBox*>& positionedObjects() { return m_positionedObjects; } + EClear clear() { return m_clear; } +private: + void reset(); + + void skipLeadingWhitespace(InlineBidiResolver&, LineInfo&, FloatingObject* lastFloatFromPreviousLine, LineWidth&); + + RenderBlockFlow* m_block; + bool m_hyphenated; + EClear m_clear; + Vector<RenderBox*> m_positionedObjects; +}; + +} + +#endif // LineBreaker_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/line/LineInfo.h b/chromium/third_party/WebKit/Source/core/rendering/line/LineInfo.h index 337da116e8b..bd5ad169678 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/line/LineInfo.h +++ b/chromium/third_party/WebKit/Source/core/rendering/line/LineInfo.h @@ -24,6 +24,8 @@ #ifndef LineInfo_h #define LineInfo_h +#include "core/rendering/line/LineWidth.h" + namespace WebCore { class LineInfo { diff --git a/chromium/third_party/WebKit/Source/core/rendering/line/LineLayoutState.h b/chromium/third_party/WebKit/Source/core/rendering/line/LineLayoutState.h new file mode 100644 index 00000000000..b62adcd9bd6 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/line/LineLayoutState.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2014 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 + * 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 LineLayoutState_h +#define LineLayoutState_h + +#include "core/rendering/RenderBlockFlow.h" +#include "platform/geometry/LayoutRect.h" + +namespace WebCore { + +// Like LayoutState for layout(), LineLayoutState keeps track of global information +// during an entire linebox tree layout pass (aka layoutInlineChildren). +class LineLayoutState { +public: + LineLayoutState(bool fullLayout, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom, RenderFlowThread* flowThread) + : m_lastFloat(0) + , m_endLine(0) + , m_floatIndex(0) + , m_endLineLogicalTop(0) + , m_endLineMatched(false) + , m_checkForFloatsFromLastLine(false) + , m_hasInlineChild(false) + , m_isFullLayout(fullLayout) + , m_repaintLogicalTop(repaintLogicalTop) + , m_repaintLogicalBottom(repaintLogicalBottom) + , m_adjustedLogicalLineTop(0) + , m_usesRepaintBounds(false) + , m_flowThread(flowThread) + { } + + void markForFullLayout() { m_isFullLayout = true; } + bool isFullLayout() const { return m_isFullLayout; } + + bool usesRepaintBounds() const { return m_usesRepaintBounds; } + + void setRepaintRange(LayoutUnit logicalHeight) + { + m_usesRepaintBounds = true; + m_repaintLogicalTop = m_repaintLogicalBottom = logicalHeight; + } + + void updateRepaintRangeFromBox(RootInlineBox* box, LayoutUnit paginationDelta = 0) + { + m_usesRepaintBounds = true; + m_repaintLogicalTop = std::min(m_repaintLogicalTop, box->logicalTopVisualOverflow() + std::min<LayoutUnit>(paginationDelta, 0)); + m_repaintLogicalBottom = std::max(m_repaintLogicalBottom, box->logicalBottomVisualOverflow() + std::max<LayoutUnit>(paginationDelta, 0)); + } + + bool endLineMatched() const { return m_endLineMatched; } + void setEndLineMatched(bool endLineMatched) { m_endLineMatched = endLineMatched; } + + bool checkForFloatsFromLastLine() const { return m_checkForFloatsFromLastLine; } + void setCheckForFloatsFromLastLine(bool check) { m_checkForFloatsFromLastLine = check; } + + bool hasInlineChild() const { return m_hasInlineChild; } + void setHasInlineChild(bool hasInlineChild) { m_hasInlineChild = hasInlineChild; } + + LineInfo& lineInfo() { return m_lineInfo; } + const LineInfo& lineInfo() const { return m_lineInfo; } + + 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; } + + FloatingObject* lastFloat() const { return m_lastFloat; } + void setLastFloat(FloatingObject* lastFloat) { m_lastFloat = lastFloat; } + + Vector<RenderBlockFlow::FloatWithRect>& floats() { return m_floats; } + + unsigned floatIndex() const { return m_floatIndex; } + void setFloatIndex(unsigned floatIndex) { m_floatIndex = floatIndex; } + + LayoutUnit adjustedLogicalLineTop() const { return m_adjustedLogicalLineTop; } + void setAdjustedLogicalLineTop(LayoutUnit value) { m_adjustedLogicalLineTop = value; } + + RenderFlowThread* flowThread() const { return m_flowThread; } + void setFlowThread(RenderFlowThread* thread) { m_flowThread = thread; } + +private: + Vector<RenderBlockFlow::FloatWithRect> m_floats; + FloatingObject* m_lastFloat; + RootInlineBox* m_endLine; + LineInfo m_lineInfo; + unsigned m_floatIndex; + LayoutUnit m_endLineLogicalTop; + bool m_endLineMatched; + bool m_checkForFloatsFromLastLine; + // Used as a performance optimization to avoid doing a full repaint when our floats + // change but we don't have any inline children. + bool m_hasInlineChild; + + bool m_isFullLayout; + + // FIXME: Should this be a range object instead of two ints? + LayoutUnit& m_repaintLogicalTop; + LayoutUnit& m_repaintLogicalBottom; + + LayoutUnit m_adjustedLogicalLineTop; + + bool m_usesRepaintBounds; + + RenderFlowThread* m_flowThread; +}; + +} + +#endif // LineLayoutState_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/LineWidth.cpp b/chromium/third_party/WebKit/Source/core/rendering/line/LineWidth.cpp index ea720e2024e..1b46843d9f4 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/LineWidth.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/line/LineWidth.cpp @@ -28,7 +28,7 @@ */ #include "config.h" -#include "core/rendering/LineWidth.h" +#include "core/rendering/line/LineWidth.h" #include "core/rendering/RenderBlock.h" #include "core/rendering/RenderRubyRun.h" @@ -40,14 +40,13 @@ LineWidth::LineWidth(RenderBlockFlow& block, bool isFirstLine, IndentTextOrNot s , m_uncommittedWidth(0) , m_committedWidth(0) , m_overhangWidth(0) + , m_trailingWhitespaceWidth(0) , m_left(0) , m_right(0) , m_availableWidth(0) - , m_segment(0) , m_isFirstLine(isFirstLine) , m_shouldIndentText(shouldIndentText) { - updateCurrentShapeSegment(); updateAvailableWidth(); } @@ -55,13 +54,8 @@ void LineWidth::updateAvailableWidth(LayoutUnit replacedHeight) { LayoutUnit height = m_block.logicalHeight(); LayoutUnit logicalHeight = m_block.minLineHeightForReplacedRenderer(m_isFirstLine, replacedHeight); - m_left = m_block.logicalLeftOffsetForLine(height, shouldIndentText(), logicalHeight); - m_right = m_block.logicalRightOffsetForLine(height, shouldIndentText(), logicalHeight); - - if (m_segment) { - m_left = std::max<float>(m_segment->logicalLeft, m_left); - m_right = std::min<float>(m_segment->logicalRight, m_right); - } + m_left = m_block.logicalLeftOffsetForLine(height, shouldIndentText(), logicalHeight).toFloat(); + m_right = m_block.logicalRightOffsetForLine(height, shouldIndentText(), logicalHeight).toFloat(); computeAvailableWidthFromLeftAndRight(); } @@ -72,47 +66,31 @@ void LineWidth::shrinkAvailableWidthForNewFloatIfNeeded(FloatingObject* newFloat if (height < m_block.logicalTopForFloat(newFloat) || height >= m_block.logicalBottomForFloat(newFloat)) return; - // When floats with shape outside are stacked, the floats are positioned based on the margin box of the float, - // not the shape's contour. Since we computed the width based on the shape contour when we added the float, - // when we add a subsequent float on the same line, we need to undo the shape delta in order to position - // based on the margin box. In order to do this, we need to walk back through the floating object list to find - // the first previous float that is on the same side as our newFloat. - ShapeOutsideInfo* previousShapeOutsideInfo = 0; - const FloatingObjectSet& floatingObjectSet = m_block.m_floatingObjects->set(); - FloatingObjectSetIterator it = floatingObjectSet.end(); - FloatingObjectSetIterator begin = floatingObjectSet.begin(); - LayoutUnit lineHeight = m_block.lineHeight(m_isFirstLine, m_block.isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); - for (--it; it != begin; --it) { - FloatingObject* previousFloat = *it; - if (previousFloat != newFloat && previousFloat->type() == newFloat->type()) { - previousShapeOutsideInfo = previousFloat->renderer()->shapeOutsideInfo(); - if (previousShapeOutsideInfo) - previousShapeOutsideInfo->updateDeltasForContainingBlockLine(&m_block, previousFloat, m_block.logicalHeight(), lineHeight); - break; - } - } - ShapeOutsideInfo* shapeOutsideInfo = newFloat->renderer()->shapeOutsideInfo(); - if (shapeOutsideInfo) - shapeOutsideInfo->updateDeltasForContainingBlockLine(&m_block, newFloat, m_block.logicalHeight(), lineHeight); + if (shapeOutsideInfo) { + LayoutUnit lineHeight = m_block.lineHeight(m_isFirstLine, m_block.isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); + shapeOutsideInfo->updateDeltasForContainingBlockLine(m_block, *newFloat, m_block.logicalHeight(), lineHeight); + } if (newFloat->type() == FloatingObject::FloatLeft) { - float newLeft = m_block.logicalRightForFloat(newFloat); - if (previousShapeOutsideInfo) - newLeft -= previousShapeOutsideInfo->rightMarginBoxDelta(); - if (shapeOutsideInfo) - newLeft += shapeOutsideInfo->rightMarginBoxDelta(); - + float newLeft = m_block.logicalRightForFloat(newFloat).toFloat(); + if (shapeOutsideInfo) { + if (shapeOutsideInfo->lineOverlapsShape()) + newLeft += shapeOutsideInfo->rightMarginBoxDelta(); + else // Per the CSS Shapes spec, If the line doesn't overlap the shape, then ignore this shape for this line. + newLeft = m_left; + } if (shouldIndentText() && m_block.style()->isLeftToRightDirection()) newLeft += floorToInt(m_block.textIndentOffset()); m_left = std::max<float>(m_left, newLeft); } else { - float newRight = m_block.logicalLeftForFloat(newFloat); - if (previousShapeOutsideInfo) - newRight -= previousShapeOutsideInfo->leftMarginBoxDelta(); - if (shapeOutsideInfo) - newRight += shapeOutsideInfo->leftMarginBoxDelta(); - + float newRight = m_block.logicalLeftForFloat(newFloat).toFloat(); + if (shapeOutsideInfo) { + if (shapeOutsideInfo->lineOverlapsShape()) + newRight += shapeOutsideInfo->leftMarginBoxDelta(); + else // Per the CSS Shapes spec, If the line doesn't overlap the shape, then ignore this shape for this line. + newRight = m_right; + } if (shouldIndentText() && !m_block.style()->isLeftToRightDirection()) newRight -= floorToInt(m_block.textIndentOffset()); m_right = std::min<float>(m_right, newRight); @@ -141,7 +119,65 @@ void LineWidth::applyOverhang(RenderRubyRun* rubyRun, RenderObject* startRendere m_overhangWidth += startOverhang + endOverhang; } -void LineWidth::fitBelowFloats() +inline static float availableWidthAtOffset(const RenderBlockFlow& block, const LayoutUnit& offset, bool shouldIndentText, float& newLineLeft, float& newLineRight) +{ + newLineLeft = block.logicalLeftOffsetForLine(offset, shouldIndentText).toFloat(); + newLineRight = block.logicalRightOffsetForLine(offset, shouldIndentText).toFloat(); + return std::max(0.0f, newLineRight - newLineLeft); +} + +inline static float availableWidthAtOffset(const RenderBlockFlow& block, const LayoutUnit& offset, bool shouldIndentText) +{ + float newLineLeft = block.logicalLeftOffsetForLine(offset, shouldIndentText).toFloat(); + float newLineRight = block.logicalRightOffsetForLine(offset, shouldIndentText).toFloat(); + return std::max(0.0f, newLineRight - newLineLeft); +} + +void LineWidth::updateLineDimension(LayoutUnit newLineTop, LayoutUnit newLineWidth, const float& newLineLeft, const float& newLineRight) +{ + if (newLineWidth <= m_availableWidth) + return; + + m_block.setLogicalHeight(newLineTop); + m_availableWidth = newLineWidth + m_overhangWidth; + m_left = newLineLeft; + m_right = newLineRight; +} + +inline static bool isWholeLineFit(const RenderBlockFlow& block, const LayoutUnit& lineTop, LayoutUnit lineHeight, float uncommittedWidth, bool shouldIndentText) +{ + for (LayoutUnit lineBottom = lineTop; lineBottom <= lineTop + lineHeight; lineBottom++) { + LayoutUnit availableWidthAtBottom = availableWidthAtOffset(block, lineBottom, shouldIndentText); + if (availableWidthAtBottom < uncommittedWidth) + return false; + } + return true; +} + +void LineWidth::wrapNextToShapeOutside(bool isFirstLine) +{ + LayoutUnit lineHeight = m_block.lineHeight(isFirstLine, m_block.isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); + LayoutUnit lineLogicalTop = m_block.logicalHeight(); + LayoutUnit newLineTop = lineLogicalTop; + LayoutUnit floatLogicalBottom = m_block.nextFloatLogicalBottomBelow(lineLogicalTop); + + float newLineWidth; + float newLineLeft = m_left; + float newLineRight = m_right; + while (true) { + newLineWidth = availableWidthAtOffset(m_block, newLineTop, shouldIndentText(), newLineLeft, newLineRight); + if (newLineWidth >= m_uncommittedWidth && isWholeLineFit(m_block, newLineTop, lineHeight, m_uncommittedWidth, shouldIndentText())) + break; + + if (newLineTop >= floatLogicalBottom) + break; + + newLineTop++; + } + updateLineDimension(newLineTop, newLineWidth, newLineLeft, newLineRight); +} + +void LineWidth::fitBelowFloats(bool isFirstLine) { ASSERT(!m_committedWidth); ASSERT(!fitsOnLine()); @@ -151,42 +187,23 @@ void LineWidth::fitBelowFloats() float newLineWidth = m_availableWidth; float newLineLeft = m_left; float newLineRight = m_right; + + FloatingObject* lastFloatFromPreviousLine = (m_block.containsFloats() ? m_block.m_floatingObjects->set().last().get() : 0); + if (lastFloatFromPreviousLine && lastFloatFromPreviousLine->renderer()->shapeOutsideInfo()) + return wrapNextToShapeOutside(isFirstLine); + while (true) { floatLogicalBottom = m_block.nextFloatLogicalBottomBelow(lastFloatLogicalBottom, ShapeOutsideFloatShapeOffset); if (floatLogicalBottom <= lastFloatLogicalBottom) break; - newLineLeft = m_block.logicalLeftOffsetForLine(floatLogicalBottom, shouldIndentText()); - newLineRight = m_block.logicalRightOffsetForLine(floatLogicalBottom, shouldIndentText()); - newLineWidth = max(0.0f, newLineRight - newLineLeft); + newLineWidth = availableWidthAtOffset(m_block, floatLogicalBottom, shouldIndentText(), newLineLeft, newLineRight); lastFloatLogicalBottom = floatLogicalBottom; - // FIXME: This code should be refactored to incorporate with the code above. - ShapeInsideInfo* shapeInsideInfo = m_block.layoutShapeInsideInfo(); - if (shapeInsideInfo) { - LayoutUnit logicalOffsetFromShapeContainer = m_block.logicalOffsetFromShapeAncestorContainer(shapeInsideInfo->owner()).height(); - LayoutUnit lineHeight = m_block.lineHeight(false, m_block.isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); - shapeInsideInfo->updateSegmentsForLine(lastFloatLogicalBottom + logicalOffsetFromShapeContainer, lineHeight); - updateCurrentShapeSegment(); - updateAvailableWidth(); - } - if (newLineWidth >= m_uncommittedWidth) break; } - - if (newLineWidth > m_availableWidth) { - m_block.setLogicalHeight(lastFloatLogicalBottom); - m_availableWidth = newLineWidth + m_overhangWidth; - m_left = newLineLeft; - m_right = newLineRight; - } -} - -void LineWidth::updateCurrentShapeSegment() -{ - if (ShapeInsideInfo* shapeInsideInfo = m_block.layoutShapeInsideInfo()) - m_segment = shapeInsideInfo->currentSegment(); + updateLineDimension(lastFloatLogicalBottom, newLineWidth, newLineLeft, newLineRight); } void LineWidth::computeAvailableWidthFromLeftAndRight() diff --git a/chromium/third_party/WebKit/Source/core/rendering/LineWidth.h b/chromium/third_party/WebKit/Source/core/rendering/line/LineWidth.h index 59e1442445e..c9346b770b7 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/LineWidth.h +++ b/chromium/third_party/WebKit/Source/core/rendering/line/LineWidth.h @@ -35,14 +35,12 @@ namespace WebCore { class FloatingObject; -class RenderBlock; class RenderObject; class RenderRubyRun; class RenderBlockFlow; -struct LineSegment; - enum IndentTextOrNot { DoNotIndentText, IndentText }; +enum WhitespaceTreatment { ExcludeWhitespace, IncludeWhitespace }; class LineWidth { public: @@ -50,35 +48,41 @@ public: bool fitsOnLine() const { return currentWidth() <= (m_availableWidth + LayoutUnit::epsilon()); } bool fitsOnLine(float extra) const { return currentWidth() + extra <= (m_availableWidth + LayoutUnit::epsilon()); } + bool fitsOnLine(float extra, WhitespaceTreatment whitespaceTreatment) const + { + return currentWidth() - (whitespaceTreatment == ExcludeWhitespace ? trailingWhitespaceWidth() : 0) + extra <= (m_availableWidth + LayoutUnit::epsilon()); + } float currentWidth() const { return m_committedWidth + m_uncommittedWidth; } // FIXME: We should eventually replace these three functions by ones that work on a higher abstraction. float uncommittedWidth() const { return m_uncommittedWidth; } float committedWidth() const { return m_committedWidth; } float availableWidth() const { return m_availableWidth; } + float trailingWhitespaceWidth() const { return m_trailingWhitespaceWidth; } void updateAvailableWidth(LayoutUnit minimumHeight = 0); void shrinkAvailableWidthForNewFloatIfNeeded(FloatingObject*); void addUncommittedWidth(float delta) { m_uncommittedWidth += delta; } void commit(); void applyOverhang(RenderRubyRun*, RenderObject* startRenderer, RenderObject* endRenderer); - void fitBelowFloats(); - - void updateCurrentShapeSegment(); + void fitBelowFloats(bool isFirstLine = false); + void setTrailingWhitespaceWidth(float width) { m_trailingWhitespaceWidth = width; } bool shouldIndentText() const { return m_shouldIndentText == IndentText; } private: void computeAvailableWidthFromLeftAndRight(); + void updateLineDimension(LayoutUnit newLineTop, LayoutUnit newLineWidth, const float& newLineLeft, const float& newLineRight); + void wrapNextToShapeOutside(bool isFirstLine); RenderBlockFlow& m_block; float m_uncommittedWidth; float m_committedWidth; float m_overhangWidth; // The amount by which |m_availableWidth| has been inflated to account for possible contraction due to ruby overhang. + float m_trailingWhitespaceWidth; float m_left; float m_right; float m_availableWidth; - const LineSegment* m_segment; bool m_isFirstLine; IndentTextOrNot m_shouldIndentText; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/RegionOversetState.h b/chromium/third_party/WebKit/Source/core/rendering/line/RenderTextInfo.h index e29e370a20a..0ad1c598a25 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RegionOversetState.h +++ b/chromium/third_party/WebKit/Source/core/rendering/line/RenderTextInfo.h @@ -1,4 +1,8 @@ /* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved. + * Copyright (C) 2010 Google Inc. 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 @@ -16,18 +20,28 @@ * */ -#ifndef RegionOversetState_h -#define RegionOversetState_h +#ifndef RenderTextInfo_h +#define RenderTextInfo_h + +#include "platform/text/TextBreakIterator.h" namespace WebCore { -enum RegionOversetState { - RegionUndefined, - RegionEmpty, - RegionFit, - RegionOverset +class Font; +class RenderText; + +struct RenderTextInfo { + RenderTextInfo() + : m_text(0) + , m_font(0) + { + } + + RenderText* m_text; + LazyLineBreakIterator m_lineBreakIterator; + const Font* m_font; }; } // namespace WebCore -#endif // RegionOversetState_h +#endif // RenderTextInfo_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/line/TrailingObjects.cpp b/chromium/third_party/WebKit/Source/core/rendering/line/TrailingObjects.cpp new file mode 100644 index 00000000000..62c489b84b5 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/line/TrailingObjects.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2014 Adobe Systems Inc. + * + * 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" +#include "core/rendering/line/TrailingObjects.h" + +#include "core/rendering/InlineIterator.h" + +namespace WebCore { + +void TrailingObjects::updateMidpointsForTrailingObjects(LineMidpointState& lineMidpointState, const InlineIterator& lBreak, CollapseFirstSpaceOrNot collapseFirstSpace) +{ + if (!m_whitespace) + return; + + // This object is either going to be part of the last midpoint, or it is going to be the actual endpoint. + // In both cases we just decrease our pos by 1 level to exclude the space, allowing it to - in effect - collapse into the newline. + if (lineMidpointState.numMidpoints() % 2) { + // Find the trailing space object's midpoint. + int trailingSpaceMidpoint = lineMidpointState.numMidpoints() - 1; + for ( ; trailingSpaceMidpoint > 0 && lineMidpointState.midpoints()[trailingSpaceMidpoint].object() != m_whitespace; --trailingSpaceMidpoint) { } + ASSERT(trailingSpaceMidpoint >= 0); + if (collapseFirstSpace == CollapseFirstSpace) + lineMidpointState.midpoints()[trailingSpaceMidpoint].setOffset(lineMidpointState.midpoints()[trailingSpaceMidpoint].offset() -1); + + // Now make sure every single trailingPositionedBox following the trailingSpaceMidpoint properly stops and starts + // ignoring spaces. + size_t currentMidpoint = trailingSpaceMidpoint + 1; + for (size_t i = 0; i < m_objects.size(); ++i) { + if (currentMidpoint >= lineMidpointState.numMidpoints()) { + // We don't have a midpoint for this box yet. + lineMidpointState.ensureLineBoxInsideIgnoredSpaces(m_objects[i]); + } else { + ASSERT(lineMidpointState.midpoints()[currentMidpoint].object() == m_objects[i]); + ASSERT(lineMidpointState.midpoints()[currentMidpoint + 1].object() == m_objects[i]); + } + currentMidpoint += 2; + } + } else if (!lBreak.object()) { + ASSERT(m_whitespace->isText()); + ASSERT(collapseFirstSpace == CollapseFirstSpace); + // Add a new end midpoint that stops right at the very end. + unsigned length = m_whitespace->textLength(); + unsigned pos = length >= 2 ? length - 2 : UINT_MAX; + InlineIterator endMid(0, m_whitespace, pos); + lineMidpointState.startIgnoringSpaces(endMid); + for (size_t i = 0; i < m_objects.size(); ++i) { + lineMidpointState.ensureLineBoxInsideIgnoredSpaces(m_objects[i]); + } + } +} + +} diff --git a/chromium/third_party/WebKit/Source/core/rendering/line/TrailingObjects.h b/chromium/third_party/WebKit/Source/core/rendering/line/TrailingObjects.h new file mode 100644 index 00000000000..72b1369ab20 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/line/TrailingObjects.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2014 Adobe Systems Inc. + * + * 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 TrailingObjects_h +#define TrailingObjects_h + +#include "wtf/Vector.h" + +namespace WebCore { + +class InlineIterator; +class RenderObject; +class RenderText; + +struct BidiRun; + +template <class Iterator, class Run> class BidiResolver; +template <class Iterator> class MidpointState; +typedef BidiResolver<InlineIterator, BidiRun> InlineBidiResolver; +typedef MidpointState<InlineIterator> LineMidpointState; + +// This class allows us to ensure lineboxes are created in the right place on the line when +// an out-of-flow positioned object or an empty inline is encountered between a trailing space +// and subsequent spaces and we want to ignore (i.e. collapse) surplus whitespace. So for example: +// <div>X <span></span> Y</div> +// or +// <div>X <div style="position: absolute"></div> Y</div> +// In both of the above snippets the inline and the positioned object occur after a trailing space +// and before a space that will cause our line breaking algorithm to start ignoring spaces. When it +// does that we want to ensure that the inline/positioned object gets a linebox and that it is part +// of the collapsed whitespace. So to achieve this we use appendObjectIfNeeded() to keep track of +// objects encountered after a trailing whitespace and updateMidpointsForTrailingObjects() to put +// them in the right place when we start ignoring surplus whitespace. + +class TrailingObjects { +public: + TrailingObjects() + : m_whitespace(0) + { + } + + void setTrailingWhitespace(RenderText* whitespace) + { + ASSERT(whitespace); + m_whitespace = whitespace; + } + + void clear() + { + m_whitespace = 0; + // Using resize(0) rather than clear() here saves 2% on + // PerformanceTests/Layout/line-layout.html because we avoid freeing and + // re-allocating the underlying buffer repeatedly. + m_objects.resize(0); + } + + void appendObjectIfNeeded(RenderObject* object) + { + if (m_whitespace) + m_objects.append(object); + } + + enum CollapseFirstSpaceOrNot { DoNotCollapseFirstSpace, CollapseFirstSpace }; + + void updateMidpointsForTrailingObjects(LineMidpointState&, const InlineIterator& lBreak, CollapseFirstSpaceOrNot); + +private: + RenderText* m_whitespace; + Vector<RenderObject*, 4> m_objects; +}; + +} + +#endif // TrailingObjects_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/line/WordMeasurement.h b/chromium/third_party/WebKit/Source/core/rendering/line/WordMeasurement.h new file mode 100644 index 00000000000..46803dd0c56 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/line/WordMeasurement.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2013 Adobe Systems Incorporated. + * + * 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 WordMeasurement_h +#define WordMeasurement_h + +#include "platform/fonts/SimpleFontData.h" +#include "wtf/HashSet.h" + +namespace WebCore { + +class RenderText; + +class WordMeasurement { +public: + WordMeasurement() + : renderer(0) + , width(0) + , startOffset(0) + , endOffset(0) + { + } + + RenderText* renderer; + float width; + int startOffset; + int endOffset; + HashSet<const SimpleFontData*> fallbackFonts; +}; + +} // namespace WebCore + +#endif // WordMeasurement_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShape.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShape.cpp index 86c9136ac90..bba80270c55 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShape.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShape.cpp @@ -42,14 +42,6 @@ LayoutRect BoxShape::shapeMarginLogicalBoundingBox() const return static_cast<LayoutRect>(marginBounds); } -LayoutRect BoxShape::shapePaddingLogicalBoundingBox() const -{ - FloatRect paddingBounds(m_bounds.rect()); - if (shapePadding() > 0) - paddingBounds.inflate(-shapePadding()); - return static_cast<LayoutRect>(paddingBounds); -} - FloatRoundedRect BoxShape::shapeMarginBounds() const { FloatRoundedRect marginBounds(m_bounds); @@ -60,24 +52,14 @@ FloatRoundedRect BoxShape::shapeMarginBounds() const return marginBounds; } -FloatRoundedRect BoxShape::shapePaddingBounds() const -{ - FloatRoundedRect paddingBounds(m_bounds); - if (shapePadding() > 0) { - paddingBounds.inflate(-shapePadding()); - paddingBounds.expandRadii(-shapePadding()); - } - return paddingBounds; -} - void BoxShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const { const FloatRoundedRect& marginBounds = shapeMarginBounds(); if (marginBounds.isEmpty() || !lineOverlapsShapeMarginBounds(logicalTop, logicalHeight)) return; - float y1 = logicalTop; - float y2 = logicalTop + logicalHeight; + float y1 = logicalTop.toFloat(); + float y2 = (logicalTop + logicalHeight).toFloat(); const FloatRect& rect = marginBounds.rect(); if (!marginBounds.isRounded()) { @@ -85,11 +67,25 @@ void BoxShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHei return; } + float topCornerMaxY = std::max<float>(marginBounds.topLeftCorner().maxY(), marginBounds.topRightCorner().maxY()); + float bottomCornerMinY = std::min<float>(marginBounds.bottomLeftCorner().y(), marginBounds.bottomRightCorner().y()); + + if (topCornerMaxY <= bottomCornerMinY && y1 <= topCornerMaxY && y2 >= bottomCornerMinY) { + result.append(LineSegment(rect.x(), rect.maxX())); + return; + } + float x1 = rect.maxX(); float x2 = rect.x(); float minXIntercept; float maxXIntercept; + if (y1 <= marginBounds.topLeftCorner().maxY() && y2 >= marginBounds.bottomLeftCorner().y()) + x1 = rect.x(); + + if (y1 <= marginBounds.topRightCorner().maxY() && y2 >= marginBounds.bottomRightCorner().y()) + x2 = rect.maxX(); + if (marginBounds.xInterceptsAtY(y1, minXIntercept, maxXIntercept)) { x1 = std::min<float>(x1, minXIntercept); x2 = std::max<float>(x2, maxXIntercept); @@ -104,27 +100,11 @@ void BoxShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHei result.append(LineSegment(x1, x2)); } -void BoxShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const +void BoxShape::buildDisplayPaths(DisplayPaths& paths) const { - const FloatRoundedRect& paddingBounds = shapePaddingBounds(); - if (paddingBounds.isEmpty()) - return; - - const FloatRect& rect = paddingBounds.rect(); - if (logicalTop < rect.y() || logicalTop + logicalHeight > rect.maxY()) - return; - - // FIXME: this method is only a stub, https://bugs.webkit.org/show_bug.cgi?id=124605. - - result.append(LineSegment(rect.x(), rect.maxX())); -} - -bool BoxShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize&, LayoutUnit& result) const -{ - // FIXME: this method is only a stub, https://bugs.webkit.org/show_bug.cgi?id=124606. - - result = minLogicalIntervalTop; - return true; + paths.shape.addRoundedRect(m_bounds.rect(), m_bounds.radii().topLeft(), m_bounds.radii().topRight(), m_bounds.radii().bottomLeft(), m_bounds.radii().bottomRight()); + if (shapeMargin()) + paths.marginShape.addRoundedRect(shapeMarginBounds().rect(), shapeMarginBounds().radii().topLeft(), shapeMarginBounds().radii().topRight(), shapeMarginBounds().radii().bottomLeft(), shapeMarginBounds().radii().bottomRight()); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShape.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShape.h index 823187a7ca9..06a51489615 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShape.h +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShape.h @@ -35,7 +35,7 @@ namespace WebCore { -class BoxShape : public Shape { +class BoxShape FINAL : public Shape { public: BoxShape(const FloatRoundedRect& bounds) : Shape() @@ -44,15 +44,12 @@ public: } virtual LayoutRect shapeMarginLogicalBoundingBox() const OVERRIDE; - virtual LayoutRect shapePaddingLogicalBoundingBox() const OVERRIDE; virtual bool isEmpty() const OVERRIDE { return m_bounds.isEmpty(); } virtual void getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const OVERRIDE; - virtual void getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const OVERRIDE; - virtual bool firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit&) const OVERRIDE; + virtual void buildDisplayPaths(DisplayPaths&) const OVERRIDE; private: FloatRoundedRect shapeMarginBounds() const; - FloatRoundedRect shapePaddingBounds() const; FloatRoundedRect m_bounds; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShapeTest.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShapeTest.cpp index 9b1f50193f1..74538f391fd 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShapeTest.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShapeTest.cpp @@ -31,6 +31,8 @@ #include "core/rendering/shapes/BoxShape.h" +#include "platform/geometry/RoundedRect.h" + #include <gtest/gtest.h> namespace WebCore { @@ -39,9 +41,9 @@ class BoxShapeTest : public ::testing::Test { protected: BoxShapeTest() { } - PassOwnPtr<Shape> createBoxShape(const LayoutSize& size, float shapeMargin, float shapePadding) + PassOwnPtr<Shape> createBoxShape(const RoundedRect& bounds, float shapeMargin) { - return Shape::createLayoutBoxShape(size, TopToBottomWritingMode, Length(shapeMargin, Fixed), Length(shapePadding, Fixed)); + return Shape::createLayoutBoxShape(bounds, TopToBottomWritingMode, shapeMargin); } }; @@ -56,8 +58,10 @@ using namespace WebCore; SegmentList result; \ shapePtr->getExcludedIntervals(lineTop, lineHeight, result); \ EXPECT_EQ(1u, result.size()); \ - EXPECT_EQ(expectedLeft, result[0].logicalLeft); \ - EXPECT_EQ(expectedRight, result[0].logicalRight); \ + if (result.size() == 1u) { \ + EXPECT_FLOAT_EQ(expectedLeft, result[0].logicalLeft); \ + EXPECT_FLOAT_EQ(expectedRight, result[0].logicalRight); \ + } \ } #define TEST_NO_EXCLUDED_INTERVAL(shapePtr, lineTop, lineHeight) \ @@ -67,13 +71,21 @@ using namespace WebCore; EXPECT_EQ(0u, result.size()); \ } +/* The BoxShape is based on a 100x50 rectangle at 0,0. The shape-margin value is 10, + * so the shapeMarginBoundingBox rectangle is 120x70 at -10,-10: + * + * -10,-10 110,-10 + * +--------+ + * | | + * +--------+ + * -10,60 60,60 + */ TEST_F(BoxShapeTest, zeroRadii) { - OwnPtr<Shape> shape = createBoxShape(LayoutSize(100, 50), 10, 20); + OwnPtr<Shape> shape = createBoxShape(RoundedRect(0, 0, 100, 50), 10); EXPECT_FALSE(shape->isEmpty()); EXPECT_EQ(LayoutRect(-10, -10, 120, 70), shape->shapeMarginLogicalBoundingBox()); - EXPECT_EQ(LayoutRect(20, 20, 60, 10), shape->shapePaddingLogicalBoundingBox()); // A BoxShape's bounds include the top edge but not the bottom edge. // Similarly a "line", specified as top,height to the overlap methods, @@ -98,16 +110,34 @@ TEST_F(BoxShapeTest, zeroRadii) TEST_NO_EXCLUDED_INTERVAL(shape, -12, 2); TEST_NO_EXCLUDED_INTERVAL(shape, 60, 1); TEST_NO_EXCLUDED_INTERVAL(shape, 100, 200); +} + +/* BoxShape geometry for this test. Corner radii are in parens, x and y intercepts + * for the elliptical corners are noted. The rectangle itself is at 0,0 with width and height 100. + * + * (10, 15) x=10 x=90 (10, 20) + * (--+---------+--) + * y=15 +--| |-+ y=20 + * | | + * | | + * y=85 + -| |- + y=70 + * (--+---------+--) + * (25, 15) x=25 x=80 (20, 30) + */ +TEST_F(BoxShapeTest, getIntervals) +{ + const RoundedRect::Radii cornerRadii(IntSize(10, 15), IntSize(10, 20), IntSize(25, 15), IntSize(20, 30)); + OwnPtr<Shape> shape = createBoxShape(RoundedRect(IntRect(0, 0, 100, 100), cornerRadii), 0); + EXPECT_FALSE(shape->isEmpty()); - EXPECT_TRUE(shape->lineOverlapsShapePaddingBounds(21, 1)); - EXPECT_TRUE(shape->lineOverlapsShapePaddingBounds(20, 0)); - EXPECT_TRUE(shape->lineOverlapsShapePaddingBounds(-10, 200)); - EXPECT_TRUE(shape->lineOverlapsShapePaddingBounds(25, 35)); - EXPECT_TRUE(shape->lineOverlapsShapePaddingBounds(29, 1)); + EXPECT_EQ(LayoutRect(0, 0, 100, 100), shape->shapeMarginLogicalBoundingBox()); - EXPECT_FALSE(shape->lineOverlapsShapePaddingBounds(18, 2)); - EXPECT_FALSE(shape->lineOverlapsShapePaddingBounds(30, 1)); - EXPECT_FALSE(shape->lineOverlapsShapePaddingBounds(100, 200)); + TEST_EXCLUDED_INTERVAL(shape, 10, 95, 0, 100); + TEST_EXCLUDED_INTERVAL(shape, 5, 25, 0, 100); + TEST_EXCLUDED_INTERVAL(shape, 15, 6, 0, 100); + TEST_EXCLUDED_INTERVAL(shape, 20, 50, 0, 100); + TEST_EXCLUDED_INTERVAL(shape, 69, 5, 0, 100); + TEST_EXCLUDED_INTERVAL(shape, 85, 10, 0, 97.320511f); } } // namespace diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/PolygonShape.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/PolygonShape.cpp index 26ddcf3606b..98cd8367e1e 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/PolygonShape.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/PolygonShape.cpp @@ -30,70 +30,11 @@ #include "config.h" #include "core/rendering/shapes/PolygonShape.h" -#include "core/rendering/shapes/ShapeInterval.h" #include "platform/geometry/LayoutPoint.h" #include "wtf/MathExtras.h" namespace WebCore { -enum EdgeIntersectionType { - Normal, - VertexMinY, - VertexMaxY, - VertexYBoth -}; - -struct EdgeIntersection { - const FloatPolygonEdge* edge; - FloatPoint point; - EdgeIntersectionType type; -}; - -static inline float leftSide(const FloatPoint& vertex1, const FloatPoint& vertex2, const FloatPoint& point) -{ - return ((point.x() - vertex1.x()) * (vertex2.y() - vertex1.y())) - ((vertex2.x() - vertex1.x()) * (point.y() - vertex1.y())); -} - -static inline bool isReflexVertex(const FloatPoint& prevVertex, const FloatPoint& vertex, const FloatPoint& nextVertex) -{ - return leftSide(prevVertex, nextVertex, vertex) < 0; -} - -static bool computeXIntersection(const FloatPolygonEdge* edgePointer, float y, EdgeIntersection& result) -{ - const FloatPolygonEdge& edge = *edgePointer; - - if (edge.minY() > y || edge.maxY() < y) - return false; - - const FloatPoint& vertex1 = edge.vertex1(); - const FloatPoint& vertex2 = edge.vertex2(); - float dy = vertex2.y() - vertex1.y(); - - float intersectionX; - EdgeIntersectionType intersectionType; - - if (!dy) { - intersectionType = VertexYBoth; - intersectionX = edge.minX(); - } else if (y == edge.minY()) { - intersectionType = VertexMinY; - intersectionX = (vertex1.y() < vertex2.y()) ? vertex1.x() : vertex2.x(); - } else if (y == edge.maxY()) { - intersectionType = VertexMaxY; - intersectionX = (vertex1.y() > vertex2.y()) ? vertex1.x() : vertex2.x(); - } else { - intersectionType = Normal; - intersectionX = ((y - vertex1.y()) * (vertex2.x() - vertex1.x()) / dy) + vertex1.x(); - } - - result.edge = edgePointer; - result.type = intersectionType; - result.point.set(intersectionX, y); - - return true; -} - static inline FloatSize inwardEdgeNormal(const FloatPolygonEdge& edge) { FloatSize edgeDelta = edge.vertex2() - edge.vertex1(); @@ -110,422 +51,113 @@ static inline FloatSize outwardEdgeNormal(const FloatPolygonEdge& edge) return -inwardEdgeNormal(edge); } -static inline void appendArc(Vector<FloatPoint>& vertices, const FloatPoint& arcCenter, float arcRadius, const FloatPoint& startArcVertex, const FloatPoint& endArcVertex, bool padding) -{ - float startAngle = atan2(startArcVertex.y() - arcCenter.y(), startArcVertex.x() - arcCenter.x()); - float endAngle = atan2(endArcVertex.y() - arcCenter.y(), endArcVertex.x() - arcCenter.x()); - const float twoPI = piFloat * 2; - if (startAngle < 0) - startAngle += twoPI; - if (endAngle < 0) - endAngle += twoPI; - float angle = (startAngle > endAngle) ? (startAngle - endAngle) : (startAngle + twoPI - endAngle); - const float arcSegmentCount = 6; // An even number so that one arc vertex will be eactly arcRadius from arcCenter. - float arcSegmentAngle = ((padding) ? -angle : twoPI - angle) / arcSegmentCount; - - vertices.append(startArcVertex); - for (unsigned i = 1; i < arcSegmentCount; ++i) { - float angle = startAngle + arcSegmentAngle * i; - vertices.append(arcCenter + FloatPoint(cos(angle) * arcRadius, sin(angle) * arcRadius)); - } - vertices.append(endArcVertex); -} - -static inline void snapVerticesToLayoutUnitGrid(Vector<FloatPoint>& vertices) -{ - for (unsigned i = 0; i < vertices.size(); ++i) - vertices[i] = flooredLayoutPoint(vertices[i]); -} - -static inline PassOwnPtr<FloatPolygon> computeShapePaddingBounds(const FloatPolygon& polygon, float padding, WindRule fillRule) -{ - OwnPtr<Vector<FloatPoint> > paddedVertices = adoptPtr(new Vector<FloatPoint>()); - FloatPoint intersection; - - for (unsigned i = 0; i < polygon.numberOfEdges(); ++i) { - const FloatPolygonEdge& thisEdge = polygon.edgeAt(i); - const FloatPolygonEdge& prevEdge = thisEdge.previousEdge(); - OffsetPolygonEdge thisOffsetEdge(thisEdge, inwardEdgeNormal(thisEdge) * padding); - OffsetPolygonEdge prevOffsetEdge(prevEdge, inwardEdgeNormal(prevEdge) * padding); - - if (prevOffsetEdge.intersection(thisOffsetEdge, intersection)) - paddedVertices->append(intersection); - else if (isReflexVertex(prevEdge.vertex1(), thisEdge.vertex1(), thisEdge.vertex2())) - appendArc(*paddedVertices, thisEdge.vertex1(), padding, prevOffsetEdge.vertex2(), thisOffsetEdge.vertex1(), true); - } - - snapVerticesToLayoutUnitGrid(*paddedVertices); - return adoptPtr(new FloatPolygon(paddedVertices.release(), fillRule)); -} - -static inline PassOwnPtr<FloatPolygon> computeShapeMarginBounds(const FloatPolygon& polygon, float margin, WindRule fillRule) -{ - OwnPtr<Vector<FloatPoint> > marginVertices = adoptPtr(new Vector<FloatPoint>()); - FloatPoint intersection; - - for (unsigned i = 0; i < polygon.numberOfEdges(); ++i) { - const FloatPolygonEdge& thisEdge = polygon.edgeAt(i); - const FloatPolygonEdge& prevEdge = thisEdge.previousEdge(); - OffsetPolygonEdge thisOffsetEdge(thisEdge, outwardEdgeNormal(thisEdge) * margin); - OffsetPolygonEdge prevOffsetEdge(prevEdge, outwardEdgeNormal(prevEdge) * margin); - - if (prevOffsetEdge.intersection(thisOffsetEdge, intersection)) - marginVertices->append(intersection); - else - appendArc(*marginVertices, thisEdge.vertex1(), margin, prevOffsetEdge.vertex2(), thisOffsetEdge.vertex1(), false); - } - - snapVerticesToLayoutUnitGrid(*marginVertices); - return adoptPtr(new FloatPolygon(marginVertices.release(), fillRule)); -} +static inline bool overlapsYRange(const FloatRect& rect, float y1, float y2) { return !rect.isEmpty() && y2 >= y1 && y2 >= rect.y() && y1 <= rect.maxY(); } -const FloatPolygon& PolygonShape::shapePaddingBounds() const +float OffsetPolygonEdge::xIntercept(float y) const { - ASSERT(shapePadding() >= 0); - if (!shapePadding() || m_polygon.isEmpty()) - return m_polygon; + ASSERT(y >= minY() && y <= maxY()); - if (!m_paddingBounds) - m_paddingBounds = computeShapePaddingBounds(m_polygon, shapePadding(), m_polygon.fillRule()); + if (vertex1().y() == vertex2().y() || vertex1().x() == vertex2().x()) + return minX(); + if (y == minY()) + return vertex1().y() < vertex2().y() ? vertex1().x() : vertex2().x(); + if (y == maxY()) + return vertex1().y() > vertex2().y() ? vertex1().x() : vertex2().x(); - return *m_paddingBounds; + return vertex1().x() + ((y - vertex1().y()) * (vertex2().x() - vertex1().x()) / (vertex2().y() - vertex1().y())); } -const FloatPolygon& PolygonShape::shapeMarginBounds() const +FloatShapeInterval OffsetPolygonEdge::clippedEdgeXRange(float y1, float y2) const { - ASSERT(shapeMargin() >= 0); - if (!shapeMargin() || m_polygon.isEmpty()) - return m_polygon; + if (!overlapsYRange(y1, y2) || (y1 == maxY() && minY() <= y1) || (y2 == minY() && maxY() >= y2)) + return FloatShapeInterval(); - if (!m_marginBounds) - m_marginBounds = computeShapeMarginBounds(m_polygon, shapeMargin(), m_polygon.fillRule()); + if (isWithinYRange(y1, y2)) + return FloatShapeInterval(minX(), maxX()); - return *m_marginBounds; -} - -static inline bool getVertexIntersectionVertices(const EdgeIntersection& intersection, FloatPoint& prevVertex, FloatPoint& thisVertex, FloatPoint& nextVertex) -{ - if (intersection.type != VertexMinY && intersection.type != VertexMaxY) - return false; - - ASSERT(intersection.edge && intersection.edge->polygon()); - const FloatPolygon& polygon = *(intersection.edge->polygon()); - const FloatPolygonEdge& thisEdge = *(intersection.edge); + // Clip the edge line segment to the vertical range y1,y2 and then return + // the clipped line segment's horizontal range. - if ((intersection.type == VertexMinY && (thisEdge.vertex1().y() < thisEdge.vertex2().y())) - || (intersection.type == VertexMaxY && (thisEdge.vertex1().y() > thisEdge.vertex2().y()))) { - prevVertex = polygon.vertexAt(thisEdge.previousEdge().vertexIndex1()); - thisVertex = polygon.vertexAt(thisEdge.vertexIndex1()); - nextVertex = polygon.vertexAt(thisEdge.vertexIndex2()); + FloatPoint minYVertex; + FloatPoint maxYVertex; + if (vertex1().y() < vertex2().y()) { + minYVertex = vertex1(); + maxYVertex = vertex2(); } else { - prevVertex = polygon.vertexAt(thisEdge.vertexIndex1()); - thisVertex = polygon.vertexAt(thisEdge.vertexIndex2()); - nextVertex = polygon.vertexAt(thisEdge.nextEdge().vertexIndex2()); + minYVertex = vertex2(); + maxYVertex = vertex1(); } - - return true; -} - -static inline bool appendIntervalX(float x, bool inside, FloatShapeIntervals& result) -{ - if (!inside) - result.append(FloatShapeInterval(x, x)); - else - result.last().setX2(x); - - return !inside; + float xForY1 = (minYVertex.y() < y1) ? xIntercept(y1) : minYVertex.x(); + float xForY2 = (maxYVertex.y() > y2) ? xIntercept(y2) : maxYVertex.x(); + return FloatShapeInterval(std::min(xForY1, xForY2), std::max(xForY1, xForY2)); } -static bool compareEdgeIntersectionX(const EdgeIntersection& intersection1, const EdgeIntersection& intersection2) +static float circleXIntercept(float y, float radius) { - float x1 = intersection1.point.x(); - float x2 = intersection2.point.x(); - return (x1 == x2) ? intersection1.type < intersection2.type : x1 < x2; + ASSERT(radius > 0); + return radius * sqrt(1 - (y * y) / (radius * radius)); } -static void computeXIntersections(const FloatPolygon& polygon, float y, bool isMinY, FloatShapeIntervals& result) +static FloatShapeInterval clippedCircleXRange(const FloatPoint& center, float radius, float y1, float y2) { - Vector<const FloatPolygonEdge*> edges; - if (!polygon.overlappingEdges(y, y, edges)) - return; - - Vector<EdgeIntersection> intersections; - EdgeIntersection intersection; - for (unsigned i = 0; i < edges.size(); ++i) { - if (computeXIntersection(edges[i], y, intersection) && intersection.type != VertexYBoth) - intersections.append(intersection); - } - - if (intersections.size() < 2) - return; - - std::sort(intersections.begin(), intersections.end(), WebCore::compareEdgeIntersectionX); - - unsigned index = 0; - int windCount = 0; - bool inside = false; + if (y1 > center.y() + radius || y2 < center.y() - radius) + return FloatShapeInterval(); - while (index < intersections.size()) { - const EdgeIntersection& thisIntersection = intersections[index]; - if (index + 1 < intersections.size()) { - const EdgeIntersection& nextIntersection = intersections[index + 1]; - if ((thisIntersection.point.x() == nextIntersection.point.x()) && (thisIntersection.type == VertexMinY || thisIntersection.type == VertexMaxY)) { - if (thisIntersection.type == nextIntersection.type) { - // Skip pairs of intersections whose types are VertexMaxY,VertexMaxY and VertexMinY,VertexMinY. - index += 2; - } else { - // Replace pairs of intersections whose types are VertexMinY,VertexMaxY or VertexMaxY,VertexMinY with one intersection. - ++index; - } - continue; - } - } - - bool edgeCrossing = thisIntersection.type == Normal; - if (!edgeCrossing) { - FloatPoint prevVertex; - FloatPoint thisVertex; - FloatPoint nextVertex; - - if (getVertexIntersectionVertices(thisIntersection, prevVertex, thisVertex, nextVertex)) { - if (nextVertex.y() == y) - edgeCrossing = (isMinY) ? prevVertex.y() > y : prevVertex.y() < y; - else if (prevVertex.y() == y) - edgeCrossing = (isMinY) ? nextVertex.y() > y : nextVertex.y() < y; - else - edgeCrossing = true; - } - } + if (center.y() >= y1 && center.y() <= y2) + return FloatShapeInterval(center.x() - radius, center.x() + radius); - if (edgeCrossing && polygon.fillRule() == RULE_NONZERO) { - const FloatPolygonEdge& thisEdge = *thisIntersection.edge; - windCount += (thisEdge.vertex2().y() > thisEdge.vertex1().y()) ? 1 : -1; - } - - if (edgeCrossing && (!inside || !windCount)) - inside = appendIntervalX(thisIntersection.point.x(), inside, result); + // Clip the circle to the vertical range y1,y2 and return the extent of the clipped circle's + // projection on the X axis - ++index; - } + float xi = circleXIntercept((y2 < center.y() ? y2 : y1) - center.y(), radius); + return FloatShapeInterval(center.x() - xi, center.x() + xi); } -static bool compareX1(const FloatShapeInterval a, const FloatShapeInterval& b) { return a.x1() < b.x1(); } - -static void sortAndMergeShapeIntervals(FloatShapeIntervals& intervals) +LayoutRect PolygonShape::shapeMarginLogicalBoundingBox() const { - std::sort(intervals.begin(), intervals.end(), compareX1); - - for (unsigned i = 1; i < intervals.size(); ) { - const FloatShapeInterval& thisInterval = intervals[i]; - FloatShapeInterval& previousInterval = intervals[i - 1]; - if (thisInterval.overlaps(previousInterval)) { - previousInterval.setX2(std::max<float>(previousInterval.x2(), thisInterval.x2())); - intervals.remove(i); - } else { - ++i; - } - } + FloatRect box = m_polygon.boundingBox(); + box.inflate(shapeMargin()); + return LayoutRect(box); } -static void computeOverlappingEdgeXProjections(const FloatPolygon& polygon, float y1, float y2, FloatShapeIntervals& result) +void PolygonShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const { - Vector<const FloatPolygonEdge*> edges; - if (!polygon.overlappingEdges(y1, y2, edges)) - return; + float y1 = logicalTop.toFloat(); + float y2 = logicalTop.toFloat() + logicalHeight.toFloat(); - EdgeIntersection intersection; - for (unsigned i = 0; i < edges.size(); ++i) { - const FloatPolygonEdge *edge = edges[i]; - float x1; - float x2; + if (m_polygon.isEmpty() || !overlapsYRange(m_polygon.boundingBox(), y1 - shapeMargin(), y2 + shapeMargin())) + return; - if (edge->minY() < y1) { - computeXIntersection(edge, y1, intersection); - x1 = intersection.point.x(); - } else { - x1 = (edge->vertex1().y() < edge->vertex2().y()) ? edge->vertex1().x() : edge->vertex2().x(); - } + Vector<const FloatPolygonEdge*> overlappingEdges; + if (!m_polygon.overlappingEdges(y1 - shapeMargin(), y2 + shapeMargin(), overlappingEdges)) + return; - if (edge->maxY() > y2) { - computeXIntersection(edge, y2, intersection); - x2 = intersection.point.x(); + FloatShapeInterval excludedInterval; + for (unsigned i = 0; i < overlappingEdges.size(); i++) { + const FloatPolygonEdge& edge = *(overlappingEdges[i]); + if (edge.maxY() == edge.minY()) + continue; + if (!shapeMargin()) { + excludedInterval.unite(OffsetPolygonEdge(edge, FloatSize()).clippedEdgeXRange(y1, y2)); } else { - x2 = (edge->vertex1().y() > edge->vertex2().y()) ? edge->vertex1().x() : edge->vertex2().x(); + excludedInterval.unite(OffsetPolygonEdge(edge, outwardEdgeNormal(edge) * shapeMargin()).clippedEdgeXRange(y1, y2)); + excludedInterval.unite(OffsetPolygonEdge(edge, inwardEdgeNormal(edge) * shapeMargin()).clippedEdgeXRange(y1, y2)); + excludedInterval.unite(clippedCircleXRange(edge.vertex1(), shapeMargin(), y1, y2)); } - - if (x1 > x2) - std::swap(x1, x2); - - if (x2 > x1) - result.append(FloatShapeInterval(x1, x2)); } - sortAndMergeShapeIntervals(result); -} - -void PolygonShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const -{ - const FloatPolygon& polygon = shapeMarginBounds(); - if (polygon.isEmpty()) - return; - - float y1 = logicalTop; - float y2 = logicalTop + logicalHeight; - - FloatShapeIntervals y1XIntervals, y2XIntervals; - computeXIntersections(polygon, y1, true, y1XIntervals); - computeXIntersections(polygon, y2, false, y2XIntervals); - - FloatShapeIntervals mergedIntervals; - FloatShapeInterval::uniteShapeIntervals(y1XIntervals, y2XIntervals, mergedIntervals); - - FloatShapeIntervals edgeIntervals; - computeOverlappingEdgeXProjections(polygon, y1, y2, edgeIntervals); - - FloatShapeIntervals excludedIntervals; - FloatShapeInterval::uniteShapeIntervals(mergedIntervals, edgeIntervals, excludedIntervals); - - for (unsigned i = 0; i < excludedIntervals.size(); ++i) { - const FloatShapeInterval& interval = excludedIntervals[i]; - result.append(LineSegment(interval.x1(), interval.x2())); - } + if (!excludedInterval.isEmpty()) + result.append(LineSegment(excludedInterval.x1(), excludedInterval.x2())); } -void PolygonShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const +void PolygonShape::buildDisplayPaths(DisplayPaths& paths) const { - const FloatPolygon& polygon = shapePaddingBounds(); - if (polygon.isEmpty()) + if (!m_polygon.numberOfVertices()) return; - - float y1 = logicalTop; - float y2 = logicalTop + logicalHeight; - - FloatShapeIntervals y1XIntervals, y2XIntervals; - computeXIntersections(polygon, y1, true, y1XIntervals); - computeXIntersections(polygon, y2, false, y2XIntervals); - - FloatShapeIntervals commonIntervals; - FloatShapeInterval::intersectShapeIntervals(y1XIntervals, y2XIntervals, commonIntervals); - - FloatShapeIntervals edgeIntervals; - computeOverlappingEdgeXProjections(polygon, y1, y2, edgeIntervals); - - FloatShapeIntervals includedIntervals; - FloatShapeInterval::subtractShapeIntervals(commonIntervals, edgeIntervals, includedIntervals); - - for (unsigned i = 0; i < includedIntervals.size(); ++i) { - const FloatShapeInterval& interval = includedIntervals[i]; - result.append(LineSegment(interval.x1(), interval.x2())); - } -} - -static inline bool firstFitRectInPolygon(const FloatPolygon& polygon, const FloatRect& rect, unsigned offsetEdgeIndex1, unsigned offsetEdgeIndex2) -{ - Vector<const FloatPolygonEdge*> edges; - if (!polygon.overlappingEdges(rect.y(), rect.maxY(), edges)) - return true; - - for (unsigned i = 0; i < edges.size(); ++i) { - const FloatPolygonEdge* edge = edges[i]; - if (edge->edgeIndex() != offsetEdgeIndex1 && edge->edgeIndex() != offsetEdgeIndex2 && edge->overlapsRect(rect)) - return false; - } - - return true; -} - -static inline bool aboveOrToTheLeft(const FloatRect& r1, const FloatRect& r2) -{ - if (r1.y() < r2.y()) - return true; - if (r1.y() == r2.y()) - return r1.x() < r2.x(); - return false; -} - -bool PolygonShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit& result) const -{ - float minIntervalTop = minLogicalIntervalTop; - float minIntervalHeight = minLogicalIntervalSize.height(); - float minIntervalWidth = minLogicalIntervalSize.width(); - - const FloatPolygon& polygon = shapePaddingBounds(); - const FloatRect boundingBox = polygon.boundingBox(); - if (minIntervalWidth > boundingBox.width()) - return false; - - float minY = std::max(boundingBox.y(), minIntervalTop); - float maxY = minY + minIntervalHeight; - - if (maxY > boundingBox.maxY()) - return false; - - Vector<const FloatPolygonEdge*> edges; - polygon.overlappingEdges(minIntervalTop, boundingBox.maxY(), edges); - - float dx = minIntervalWidth / 2; - float dy = minIntervalHeight / 2; - Vector<OffsetPolygonEdge> offsetEdges; - - for (unsigned i = 0; i < edges.size(); ++i) { - const FloatPolygonEdge& edge = *(edges[i]); - const FloatPoint& vertex0 = edge.previousEdge().vertex1(); - const FloatPoint& vertex1 = edge.vertex1(); - const FloatPoint& vertex2 = edge.vertex2(); - Vector<OffsetPolygonEdge> offsetEdgeBuffer; - - if (vertex2.y() > vertex1.y() ? vertex2.x() >= vertex1.x() : vertex1.x() >= vertex2.x()) { - offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(dx, -dy))); - offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(-dx, dy))); - } else { - offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(dx, dy))); - offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(-dx, -dy))); - } - - if (isReflexVertex(vertex0, vertex1, vertex2)) { - if (vertex2.x() <= vertex1.x() && vertex0.x() <= vertex1.x()) - offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(dx, -dy), FloatSize(dx, dy))); - else if (vertex2.x() >= vertex1.x() && vertex0.x() >= vertex1.x()) - offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(-dx, -dy), FloatSize(-dx, dy))); - if (vertex2.y() <= vertex1.y() && vertex0.y() <= vertex1.y()) - offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(-dx, dy), FloatSize(dx, dy))); - else if (vertex2.y() >= vertex1.y() && vertex0.y() >= vertex1.y()) - offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(-dx, -dy), FloatSize(dx, -dy))); - } - - for (unsigned j = 0; j < offsetEdgeBuffer.size(); ++j) { - if (offsetEdgeBuffer[j].maxY() >= minY) - offsetEdges.append(offsetEdgeBuffer[j]); - } - } - - offsetEdges.append(OffsetPolygonEdge(polygon, minIntervalTop, FloatSize(0, dy))); - - FloatPoint offsetEdgesIntersection; - FloatRect firstFitRect; - bool firstFitFound = false; - - for (unsigned i = 0; i < offsetEdges.size() - 1; ++i) { - for (unsigned j = i + 1; j < offsetEdges.size(); ++j) { - if (offsetEdges[i].intersection(offsetEdges[j], offsetEdgesIntersection)) { - FloatPoint potentialFirstFitLocation(offsetEdgesIntersection.x() - dx, offsetEdgesIntersection.y() - dy); - FloatRect potentialFirstFitRect(potentialFirstFitLocation, minLogicalIntervalSize); - if ((offsetEdges[i].basis() == OffsetPolygonEdge::LineTop - || offsetEdges[j].basis() == OffsetPolygonEdge::LineTop - || potentialFirstFitLocation.y() >= minIntervalTop) - && (!firstFitFound || aboveOrToTheLeft(potentialFirstFitRect, firstFitRect)) - && polygon.contains(offsetEdgesIntersection) - && firstFitRectInPolygon(polygon, potentialFirstFitRect, offsetEdges[i].edgeIndex(), offsetEdges[j].edgeIndex())) { - firstFitFound = true; - firstFitRect = potentialFirstFitRect; - } - } - } - } - - if (firstFitFound) - result = LayoutUnit::fromFloatCeil(firstFitRect.y()); - return firstFitFound; + paths.shape.moveTo(m_polygon.vertexAt(0)); + for (size_t i = 1; i < m_polygon.numberOfVertices(); ++i) + paths.shape.addLineTo(m_polygon.vertexAt(i)); + paths.shape.closeSubpath(); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/PolygonShape.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/PolygonShape.h index 38b0d8e75c7..f7171c929f4 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/PolygonShape.h +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/PolygonShape.h @@ -31,79 +31,48 @@ #define PolygonShape_h #include "core/rendering/shapes/Shape.h" +#include "core/rendering/shapes/ShapeInterval.h" #include "platform/geometry/FloatPolygon.h" namespace WebCore { -class OffsetPolygonEdge : public VertexPair { +class OffsetPolygonEdge FINAL : public VertexPair { public: - enum Basis { - Edge, - Vertex, - LineTop - }; - OffsetPolygonEdge(const FloatPolygonEdge& edge, const FloatSize& offset) : m_vertex1(edge.vertex1() + offset) , m_vertex2(edge.vertex2() + offset) - , m_edgeIndex(edge.edgeIndex()) - , m_basis(Edge) - { - } - - OffsetPolygonEdge(const FloatPoint& reflexVertex, const FloatSize& offset1, const FloatSize& offset2) - : m_vertex1(reflexVertex + offset1) - , m_vertex2(reflexVertex + offset2) - , m_edgeIndex(-1) - , m_basis(Vertex) - { - } - - OffsetPolygonEdge(const FloatPolygon& polygon, float minLogicalIntervalTop, const FloatSize& offset) - : m_vertex1(FloatPoint(polygon.boundingBox().x(), minLogicalIntervalTop) + offset) - , m_vertex2(FloatPoint(polygon.boundingBox().maxX(), minLogicalIntervalTop) + offset) - , m_edgeIndex(-1) - , m_basis(LineTop) { } virtual const FloatPoint& vertex1() const OVERRIDE { return m_vertex1; } virtual const FloatPoint& vertex2() const OVERRIDE { return m_vertex2; } - int edgeIndex() const { return m_edgeIndex; } - Basis basis() const { return m_basis; } + + bool isWithinYRange(float y1, float y2) const { return y1 <= minY() && y2 >= maxY(); } + bool overlapsYRange(float y1, float y2) const { return y2 >= minY() && y1 <= maxY(); } + float xIntercept(float y) const; + FloatShapeInterval clippedEdgeXRange(float y1, float y2) const; private: FloatPoint m_vertex1; FloatPoint m_vertex2; - int m_edgeIndex; - Basis m_basis; }; -class PolygonShape : public Shape { +class PolygonShape FINAL : public Shape { WTF_MAKE_NONCOPYABLE(PolygonShape); public: PolygonShape(PassOwnPtr<Vector<FloatPoint> > vertices, WindRule fillRule) : Shape() , m_polygon(vertices, fillRule) - , m_marginBounds(nullptr) - , m_paddingBounds(nullptr) { } - virtual LayoutRect shapeMarginLogicalBoundingBox() const OVERRIDE { return static_cast<LayoutRect>(shapeMarginBounds().boundingBox()); } - virtual LayoutRect shapePaddingLogicalBoundingBox() const OVERRIDE { return static_cast<LayoutRect>(shapePaddingBounds().boundingBox()); } + virtual LayoutRect shapeMarginLogicalBoundingBox() const OVERRIDE; virtual bool isEmpty() const OVERRIDE { return m_polygon.isEmpty(); } virtual void getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const OVERRIDE; - virtual void getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const OVERRIDE; - virtual bool firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit&) const OVERRIDE; + virtual void buildDisplayPaths(DisplayPaths&) const OVERRIDE; private: - const FloatPolygon& shapeMarginBounds() const; - const FloatPolygon& shapePaddingBounds() const; - FloatPolygon m_polygon; - mutable OwnPtr<FloatPolygon> m_marginBounds; - mutable OwnPtr<FloatPolygon> m_paddingBounds; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/RasterShape.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/RasterShape.cpp index 78b00211519..8dda343bc66 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/RasterShape.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/RasterShape.cpp @@ -73,182 +73,67 @@ IntShapeInterval MarginIntervalGenerator::intervalAt(int y) const return IntShapeInterval(m_x1 - dx, m_x2 + dx); } -void RasterShapeIntervals::appendInterval(int y, int x1, int x2) +PassOwnPtr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginIntervals(int shapeMargin) const { - ASSERT(x2 > x1 && (intervalsAt(y).isEmpty() || x1 > intervalsAt(y).last().x2())); - m_bounds.unite(IntRect(x1, y, x2 - x1, 1)); - intervalsAt(y).append(IntShapeInterval(x1, x2)); -} - -void RasterShapeIntervals::uniteMarginInterval(int y, const IntShapeInterval& interval) -{ - ASSERT(intervalsAt(y).size() <= 1); // Each m_intervalLists entry has 0 or one interval. - - if (intervalsAt(y).isEmpty()) { - intervalsAt(y).append(interval); - } else { - IntShapeInterval& resultInterval = intervalsAt(y)[0]; - resultInterval.set(std::min(resultInterval.x1(), interval.x1()), std::max(resultInterval.x2(), interval.x2())); - } - - m_bounds.unite(IntRect(interval.x1(), y, interval.width(), 1)); -} - -static inline bool shapeIntervalsContain(const IntShapeIntervals& intervals, const IntShapeInterval& interval) -{ - for (unsigned i = 0; i < intervals.size(); i++) { - if (intervals[i].x1() > interval.x2()) - return false; - if (intervals[i].contains(interval)) - return true; - } - - return false; -} - -bool RasterShapeIntervals::contains(const IntRect& rect) const -{ - if (!bounds().contains(rect)) - return false; - - const IntShapeInterval& rectInterval = IntShapeInterval(rect.x(), rect.maxX()); - for (int y = rect.y(); y < rect.maxY(); y++) { - if (!shapeIntervalsContain(intervalsAt(y), rectInterval)) - return false; - } - - return true; -} - -static inline void appendX1Values(const IntShapeIntervals& intervals, int minIntervalWidth, Vector<int>& result) -{ - for (unsigned i = 0; i < intervals.size(); i++) { - if (intervals[i].width() >= minIntervalWidth) - result.append(intervals[i].x1()); - } -} - -bool RasterShapeIntervals::getIntervalX1Values(int y1, int y2, int minIntervalWidth, Vector<int>& result) const -{ - ASSERT(y1 >= 0 && y2 > y1); - - for (int y = y1; y < y2; y++) { - if (intervalsAt(y).isEmpty()) - return false; - } - - appendX1Values(intervalsAt(y1), minIntervalWidth, result); - for (int y = y1 + 1; y < y2; y++) { - if (intervalsAt(y) != intervalsAt(y - 1)) - appendX1Values(intervalsAt(y), minIntervalWidth, result); - } - - return true; -} - -bool RasterShapeIntervals::firstIncludedIntervalY(int minY, const IntSize& minSize, LayoutUnit& result) const -{ - minY = std::max<int>(bounds().y(), minY); - - ASSERT(minY >= 0 && minY < size()); - - if (minSize.isEmpty() || minSize.width() > bounds().width()) - return false; + int marginIntervalsSize = (offset() > shapeMargin) ? size() : size() - offset() * 2 + shapeMargin * 2; + OwnPtr<RasterShapeIntervals> result = adoptPtr(new RasterShapeIntervals(marginIntervalsSize, std::max(shapeMargin, offset()))); + MarginIntervalGenerator marginIntervalGenerator(shapeMargin); - for (int lineY = minY; lineY <= bounds().maxY() - minSize.height(); lineY++) { - Vector<int> intervalX1Values; - if (!getIntervalX1Values(lineY, lineY + minSize.height(), minSize.width(), intervalX1Values)) + for (int y = bounds().y(); y < bounds().maxY(); ++y) { + const IntShapeInterval& intervalAtY = intervalAt(y); + if (intervalAtY.isEmpty()) continue; - std::sort(intervalX1Values.begin(), intervalX1Values.end()); + marginIntervalGenerator.set(y, intervalAtY); + int marginY0 = std::max(minY(), y - shapeMargin); + int marginY1 = std::min(maxY(), y + shapeMargin + 1); - IntRect firstFitRect(IntPoint(0, 0), minSize); - for (unsigned i = 0; i < intervalX1Values.size(); i++) { - int lineX = intervalX1Values[i]; - if (i > 0 && lineX == intervalX1Values[i - 1]) - continue; - firstFitRect.setLocation(IntPoint(lineX, lineY)); - if (contains(firstFitRect)) { - result = lineY; - return true; - } + for (int marginY = y - 1; marginY >= marginY0; --marginY) { + if (marginY > bounds().y() && intervalAt(marginY).contains(intervalAtY)) + break; + result->intervalAt(marginY).unite(marginIntervalGenerator.intervalAt(marginY)); } - } - - return false; -} - -void RasterShapeIntervals::getIncludedIntervals(int y1, int y2, IntShapeIntervals& result) const -{ - ASSERT(y2 >= y1); - if (y1 < bounds().y() || y2 > bounds().maxY()) - return; + result->intervalAt(y).unite(marginIntervalGenerator.intervalAt(y)); - for (int y = y1; y < y2; y++) { - if (intervalsAt(y).isEmpty()) - return; + for (int marginY = y + 1; marginY < marginY1; ++marginY) { + if (marginY < bounds().maxY() && intervalAt(marginY).contains(intervalAtY)) + break; + result->intervalAt(marginY).unite(marginIntervalGenerator.intervalAt(marginY)); + } } - result = intervalsAt(y1); - for (int y = y1 + 1; y < y2 && !result.isEmpty(); y++) { - IntShapeIntervals intervals; - IntShapeInterval::intersectShapeIntervals(result, intervalsAt(y), intervals); - result.swap(intervals); - } + result->initializeBounds(); + return result.release(); } -void RasterShapeIntervals::getExcludedIntervals(int y1, int y2, IntShapeIntervals& result) const +void RasterShapeIntervals::initializeBounds() { - ASSERT(y2 >= y1); - - if (y2 < bounds().y() || y1 >= bounds().maxY()) - return; - - y1 = std::max(y1, bounds().y()); - y2 = std::min(y2, bounds().maxY()); - - result = intervalsAt(y1); - for (int y = y1 + 1; y < y2; y++) { - IntShapeIntervals intervals; - IntShapeInterval::uniteShapeIntervals(result, intervalsAt(y), intervals); - result.swap(intervals); + m_bounds = IntRect(); + for (int y = minY(); y < maxY(); ++y) { + const IntShapeInterval& intervalAtY = intervalAt(y); + if (intervalAtY.isEmpty()) + continue; + m_bounds.unite(IntRect(intervalAtY.x1(), y, intervalAtY.width(), 1)); } } -PassOwnPtr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginIntervals(unsigned shapeMargin) const +void RasterShapeIntervals::buildBoundsPath(Path& path) const { - OwnPtr<RasterShapeIntervals> result = adoptPtr(new RasterShapeIntervals(size(), shapeMargin)); - MarginIntervalGenerator marginIntervalGenerator(shapeMargin); - - int minY = bounds().y(); int maxY = bounds().maxY(); - - for (int y = minY; y < maxY; ++y) { - const IntShapeInterval& intervalAtY = limitIntervalAt(y); - if (intervalAtY.isEmpty()) + for (int y = bounds().y(); y < maxY; y++) { + if (intervalAt(y).isEmpty()) continue; - marginIntervalGenerator.set(y, intervalAtY); - int marginY0 = y - clampToInteger(shapeMargin); - int marginY1 = y + clampToInteger(shapeMargin); - - for (int marginY = y - 1; marginY >= marginY0; --marginY) { - if (marginY > minY && limitIntervalAt(marginY).contains(intervalAtY)) + IntShapeInterval extent = intervalAt(y); + int endY = y + 1; + for (; endY < maxY; endY++) { + if (intervalAt(endY).isEmpty() || intervalAt(endY) != extent) break; - result->uniteMarginInterval(marginY, marginIntervalGenerator.intervalAt(marginY)); - } - - result->uniteMarginInterval(y, marginIntervalGenerator.intervalAt(y)); - - for (int marginY = y + 1; marginY <= marginY1; ++marginY) { - if (marginY < maxY && limitIntervalAt(marginY).contains(intervalAtY)) - break; - result->uniteMarginInterval(marginY, marginIntervalGenerator.intervalAt(marginY)); } + path.addRect(FloatRect(extent.x1(), y, extent.width(), endY - y)); + y = endY - 1; } - - return result.release(); } const RasterShapeIntervals& RasterShape::marginIntervals() const @@ -257,58 +142,37 @@ const RasterShapeIntervals& RasterShape::marginIntervals() const if (!shapeMargin()) return *m_intervals; - unsigned marginBoundaryRadius = std::min(clampToUnsigned(ceil(shapeMargin())), std::max<unsigned>(m_imageSize.width(), m_imageSize.height())); + int shapeMarginInt = clampToPositiveInteger(ceil(shapeMargin())); + int maxShapeMarginInt = std::max(m_marginRectSize.width(), m_marginRectSize.height()) * sqrtf(2); if (!m_marginIntervals) - m_marginIntervals = m_intervals->computeShapeMarginIntervals(marginBoundaryRadius); + m_marginIntervals = m_intervals->computeShapeMarginIntervals(std::min(shapeMarginInt, maxShapeMarginInt)); return *m_marginIntervals; } -const RasterShapeIntervals& RasterShape::paddingIntervals() const -{ - ASSERT(shapePadding() >= 0); - if (!shapePadding()) - return *m_intervals; - - // FIXME: Add support for non-zero padding, see https://bugs.webkit.org/show_bug.cgi?id=116348. - return *m_intervals; -} - -static inline void appendLineSegments(const IntShapeIntervals& intervals, SegmentList& result) -{ - for (unsigned i = 0; i < intervals.size(); i++) - result.append(LineSegment(intervals[i].x1(), intervals[i].x2() + 1)); -} - void RasterShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const { const RasterShapeIntervals& intervals = marginIntervals(); if (intervals.isEmpty()) return; - IntShapeIntervals excludedIntervals; - intervals.getExcludedIntervals(logicalTop, logicalTop + logicalHeight, excludedIntervals); - appendLineSegments(excludedIntervals, result); -} - -void RasterShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const -{ - const RasterShapeIntervals& intervals = paddingIntervals(); - if (intervals.isEmpty()) + int y1 = logicalTop; + int y2 = logicalTop + logicalHeight; + ASSERT(y2 >= y1); + if (y2 < intervals.bounds().y() || y1 >= intervals.bounds().maxY()) return; - IntShapeIntervals includedIntervals; - intervals.getIncludedIntervals(logicalTop, logicalTop + logicalHeight, includedIntervals); - appendLineSegments(includedIntervals, result); -} + y1 = std::max(y1, intervals.bounds().y()); + y2 = std::min(y2, intervals.bounds().maxY()); + IntShapeInterval excludedInterval; -bool RasterShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit& result) const -{ - const RasterShapeIntervals& intervals = paddingIntervals(); - if (intervals.isEmpty()) - return false; + for (int y = y1; y < y2; y++) + excludedInterval.unite(intervals.intervalAt(y)); - return intervals.firstIncludedIntervalY(minLogicalIntervalTop.floor(), flooredIntSize(minLogicalIntervalSize), result); + // Note: |marginIntervals()| returns end-point exclusive + // intervals. |excludedInterval.x2()| contains the left-most pixel + // offset to the right of the calculated union. + result.append(LineSegment(excludedInterval.x1(), excludedInterval.x2())); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/RasterShape.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/RasterShape.h index 903eabb0527..0ca8d8a5ba9 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/RasterShape.h +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/RasterShape.h @@ -40,74 +40,69 @@ namespace WebCore { class RasterShapeIntervals { public: - RasterShapeIntervals(unsigned size, unsigned shapeMargin = 0) - : m_shapeMargin(shapeMargin) + RasterShapeIntervals(unsigned size, int offset = 0) + : m_offset(offset) { - m_intervalLists.resize(size + shapeMargin * 2); + m_intervals.resize(clampTo<int>(size)); } + void initializeBounds(); const IntRect& bounds() const { return m_bounds; } bool isEmpty() const { return m_bounds.isEmpty(); } - void appendInterval(int y, int x1, int x2); - void getIncludedIntervals(int y1, int y2, IntShapeIntervals& result) const; - void getExcludedIntervals(int y1, int y2, IntShapeIntervals& result) const; - bool firstIncludedIntervalY(int minY, const IntSize& minSize, LayoutUnit& result) const; - PassOwnPtr<RasterShapeIntervals> computeShapeMarginIntervals(unsigned shapeMargin) const; - -private: - int size() const { return m_intervalLists.size(); } - - IntShapeIntervals& intervalsAt(int y) + IntShapeInterval& intervalAt(int y) { - ASSERT(y + m_shapeMargin >= 0 && y + m_shapeMargin < m_intervalLists.size()); - return m_intervalLists[y + m_shapeMargin]; + ASSERT(y + m_offset >= 0 && static_cast<unsigned>(y + m_offset) < m_intervals.size()); + return m_intervals[y + m_offset]; } - const IntShapeIntervals& intervalsAt(int y) const + const IntShapeInterval& intervalAt(int y) const { - ASSERT(y + m_shapeMargin >= 0 && y + m_shapeMargin < m_intervalLists.size()); - return m_intervalLists[y + m_shapeMargin]; + ASSERT(y + m_offset >= 0 && static_cast<unsigned>(y + m_offset) < m_intervals.size()); + return m_intervals[y + m_offset]; } - IntShapeInterval limitIntervalAt(int y) const - { - const IntShapeIntervals& intervals = intervalsAt(y); - return intervals.size() ? IntShapeInterval(intervals[0].x1(), intervals.last().x2()) : IntShapeInterval(); - } + PassOwnPtr<RasterShapeIntervals> computeShapeMarginIntervals(int shapeMargin) const; + + void buildBoundsPath(Path&) const; + +private: + int size() const { return m_intervals.size(); } + int offset() const { return m_offset; } + int minY() const { return -m_offset; } + int maxY() const { return -m_offset + m_intervals.size(); } - bool contains(const IntRect&) const; - bool getIntervalX1Values(int minY, int maxY, int minIntervalWidth, Vector<int>& result) const; - void uniteMarginInterval(int y, const IntShapeInterval&); IntRect m_bounds; - Vector<IntShapeIntervals> m_intervalLists; - unsigned m_shapeMargin; + Vector<IntShapeInterval> m_intervals; + int m_offset; }; -class RasterShape : public Shape { +class RasterShape FINAL : public Shape { WTF_MAKE_NONCOPYABLE(RasterShape); public: - RasterShape(PassOwnPtr<RasterShapeIntervals> intervals, const IntSize& imageSize) - : Shape() - , m_intervals(intervals) - , m_imageSize(imageSize) + RasterShape(PassOwnPtr<RasterShapeIntervals> intervals, const IntSize& marginRectSize) + : m_intervals(intervals) + , m_marginRectSize(marginRectSize) { + m_intervals->initializeBounds(); } virtual LayoutRect shapeMarginLogicalBoundingBox() const OVERRIDE { return static_cast<LayoutRect>(marginIntervals().bounds()); } - virtual LayoutRect shapePaddingLogicalBoundingBox() const OVERRIDE { return static_cast<LayoutRect>(paddingIntervals().bounds()); } virtual bool isEmpty() const OVERRIDE { return m_intervals->isEmpty(); } virtual void getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const OVERRIDE; - virtual void getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const OVERRIDE; - virtual bool firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit&) const OVERRIDE; + virtual void buildDisplayPaths(DisplayPaths& paths) const OVERRIDE + { + m_intervals->buildBoundsPath(paths.shape); + if (shapeMargin()) + marginIntervals().buildBoundsPath(paths.marginShape); + } private: const RasterShapeIntervals& marginIntervals() const; - const RasterShapeIntervals& paddingIntervals() const; OwnPtr<RasterShapeIntervals> m_intervals; mutable OwnPtr<RasterShapeIntervals> m_marginIntervals; - IntSize m_imageSize; + IntSize m_marginRectSize; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/RectangleShape.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/RectangleShape.cpp index efe1f69831b..eaf51424c83 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/RectangleShape.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/RectangleShape.cpp @@ -40,26 +40,6 @@ static inline float ellipseXIntercept(float y, float rx, float ry) return rx * sqrt(1 - (y * y) / (ry * ry)); } -static inline float ellipseYIntercept(float x, float rx, float ry) -{ - ASSERT(rx > 0); - return ry * sqrt(1 - (x * x) / (rx * rx)); -} - -FloatRect RectangleShape::shapePaddingBounds() const -{ - ASSERT(shapePadding() >= 0); - if (!shapePadding() || isEmpty()) - return m_bounds; - - float boundsX = x() + std::min(width() / 2, shapePadding()); - float boundsY = y() + std::min(height() / 2, shapePadding()); - float boundsWidth = std::max(0.0f, width() - shapePadding() * 2); - float boundsHeight = std::max(0.0f, height() - shapePadding() * 2); - - return FloatRect(boundsX, boundsY, boundsWidth, boundsHeight); -} - FloatRect RectangleShape::shapeMarginBounds() const { ASSERT(shapeMargin() >= 0); @@ -79,8 +59,8 @@ void RectangleShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logi if (bounds.isEmpty()) return; - float y1 = logicalTop; - float y2 = logicalTop + logicalHeight; + float y1 = logicalTop.toFloat(); + float y2 = (logicalTop + logicalHeight).toFloat(); if (y2 < bounds.y() || y1 >= bounds.maxY()) return; @@ -108,112 +88,11 @@ void RectangleShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logi result.append(LineSegment(x1, x2)); } -void RectangleShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const +void RectangleShape::buildDisplayPaths(DisplayPaths& paths) const { - const FloatRect& bounds = shapePaddingBounds(); - if (bounds.isEmpty()) - return; - - float y1 = logicalTop; - float y2 = logicalTop + logicalHeight; - - if (y1 < bounds.y() || y2 > bounds.maxY()) - return; - - float x1 = bounds.x(); - float x2 = bounds.maxX(); - - float paddingRadiusX = std::max(0.0f, rx() - shapePadding()); - float paddingRadiusY = std::max(0.0f, ry() - shapePadding()); - - if (paddingRadiusX > 0) { - bool y1InterceptsCorner = y1 < bounds.y() + paddingRadiusY; - bool y2InterceptsCorner = y2 > bounds.maxY() - paddingRadiusY; - float xi = 0; - - if (y1InterceptsCorner && y2InterceptsCorner) { - if (y1 < bounds.height() + 2 * bounds.y() - y2) { - float yi = y1 - bounds.y() - paddingRadiusY; - xi = ellipseXIntercept(yi, paddingRadiusX, paddingRadiusY); - } else { - float yi = y2 - (bounds.maxY() - paddingRadiusY); - xi = ellipseXIntercept(yi, paddingRadiusX, paddingRadiusY); - } - } else if (y1InterceptsCorner) { - float yi = y1 - bounds.y() - paddingRadiusY; - xi = ellipseXIntercept(yi, paddingRadiusX, paddingRadiusY); - } else if (y2InterceptsCorner) { - float yi = y2 - (bounds.maxY() - paddingRadiusY); - xi = ellipseXIntercept(yi, paddingRadiusX, paddingRadiusY); - } - - if (y1InterceptsCorner || y2InterceptsCorner) { - x1 = bounds.x() + paddingRadiusX - xi; - x2 = bounds.maxX() - paddingRadiusX + xi; - } - } - - result.append(LineSegment(x1, x2)); -} - -static FloatPoint cornerInterceptForWidth(float width, float widthAtIntercept, float rx, float ry) -{ - float xi = (width - widthAtIntercept) / 2; - float yi = ry - ellipseYIntercept(rx - xi, rx, ry); - return FloatPoint(xi, yi); -} - -bool RectangleShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit& result) const -{ - float minIntervalTop = minLogicalIntervalTop; - float minIntervalHeight = minLogicalIntervalSize.height(); - float minIntervalWidth = minLogicalIntervalSize.width(); - - const FloatRect& bounds = shapePaddingBounds(); - if (bounds.isEmpty() || minIntervalWidth > bounds.width()) - return false; - - float minY = LayoutUnit::fromFloatCeil(std::max(bounds.y(), minIntervalTop)); - float maxY = minY + minIntervalHeight; - - if (maxY > bounds.maxY()) - return false; - - float paddingRadiusX = std::max(0.0f, rx() - shapePadding()); - float paddingRadiusY = std::max(0.0f, ry() - shapePadding()); - - bool intervalOverlapsMinCorner = minY < bounds.y() + paddingRadiusY; - bool intervalOverlapsMaxCorner = maxY > bounds.maxY() - paddingRadiusY; - - if (!intervalOverlapsMinCorner && !intervalOverlapsMaxCorner) { - result = minY; - return true; - } - - float centerY = bounds.y() + bounds.height() / 2; - bool minCornerDefinesX = fabs(centerY - minY) > fabs(centerY - maxY); - bool intervalFitsWithinCorners = minIntervalWidth + 2 * paddingRadiusX <= bounds.width(); - FloatPoint cornerIntercept = cornerInterceptForWidth(bounds.width(), minIntervalWidth, paddingRadiusX, paddingRadiusY); - - if (intervalOverlapsMinCorner && (!intervalOverlapsMaxCorner || minCornerDefinesX)) { - if (intervalFitsWithinCorners || bounds.y() + cornerIntercept.y() < minY) { - result = minY; - return true; - } - if (minIntervalHeight < bounds.height() - (2 * cornerIntercept.y())) { - result = LayoutUnit::fromFloatCeil(bounds.y() + cornerIntercept.y()); - return true; - } - } - - if (intervalOverlapsMaxCorner && (!intervalOverlapsMinCorner || !minCornerDefinesX)) { - if (intervalFitsWithinCorners || minY <= bounds.maxY() - cornerIntercept.y() - minIntervalHeight) { - result = minY; - return true; - } - } - - return false; + paths.shape.addRoundedRect(m_bounds, m_radii); + if (shapeMargin()) + paths.marginShape.addRoundedRect(shapeMarginBounds(), FloatSize(m_radii.width() + shapeMargin(), m_radii.height() + shapeMargin())); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/RectangleShape.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/RectangleShape.h index 9a9dae5522e..d47471da48f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/RectangleShape.h +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/RectangleShape.h @@ -39,7 +39,7 @@ namespace WebCore { -class RectangleShape : public Shape { +class RectangleShape FINAL : public Shape { public: RectangleShape(const FloatRect& bounds, const FloatSize& radii) : Shape() @@ -49,15 +49,12 @@ public: } virtual LayoutRect shapeMarginLogicalBoundingBox() const OVERRIDE { return static_cast<LayoutRect>(shapeMarginBounds()); } - virtual LayoutRect shapePaddingLogicalBoundingBox() const OVERRIDE { return static_cast<LayoutRect>(shapePaddingBounds()); } virtual bool isEmpty() const OVERRIDE { return m_bounds.isEmpty(); } virtual void getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const OVERRIDE; - virtual void getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const OVERRIDE; - virtual bool firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit&) const OVERRIDE; + virtual void buildDisplayPaths(DisplayPaths&) const OVERRIDE; private: FloatRect shapeMarginBounds() const; - FloatRect shapePaddingBounds() const; float rx() const { return m_radii.width(); } float ry() const { return m_radii.height(); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/Shape.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/Shape.cpp index ffe05053133..6e382254b9a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/Shape.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/Shape.cpp @@ -30,14 +30,16 @@ #include "config.h" #include "core/rendering/shapes/Shape.h" +#include "core/css/BasicShapeFunctions.h" #include "core/fetch/ImageResource.h" #include "core/rendering/shapes/BoxShape.h" #include "core/rendering/shapes/PolygonShape.h" #include "core/rendering/shapes/RasterShape.h" #include "core/rendering/shapes/RectangleShape.h" +#include "core/rendering/style/RenderStyle.h" #include "platform/LengthFunctions.h" -#include "platform/geometry/FloatRoundedRect.h" #include "platform/geometry/FloatSize.h" +#include "platform/graphics/GraphicsContext.h" #include "platform/graphics/ImageBuffer.h" #include "platform/graphics/WindRule.h" #include "wtf/MathExtras.h" @@ -45,18 +47,12 @@ namespace WebCore { -static PassOwnPtr<Shape> createBoxShape(const FloatRoundedRect& bounds) +static PassOwnPtr<Shape> createInsetShape(const FloatRoundedRect& bounds) { ASSERT(bounds.rect().width() >= 0 && bounds.rect().height() >= 0); return adoptPtr(new BoxShape(bounds)); } -static PassOwnPtr<Shape> createRectangleShape(const FloatRect& bounds, const FloatSize& radii) -{ - ASSERT(bounds.width() >= 0 && bounds.height() >= 0 && radii.width() >= 0 && radii.height() >= 0); - return adoptPtr(new RectangleShape(bounds, radii)); -} - static PassOwnPtr<Shape> createCircleShape(const FloatPoint& center, float radius) { ASSERT(radius >= 0); @@ -99,55 +95,22 @@ static inline FloatSize physicalSizeToLogical(const FloatSize& size, WritingMode return size.transposedSize(); } -static inline void ensureRadiiDoNotOverlap(FloatRect &bounds, FloatSize &radii) -{ - float widthRatio = bounds.width() / (2 * radii.width()); - float heightRatio = bounds.height() / (2 * radii.height()); - float reductionRatio = std::min<float>(widthRatio, heightRatio); - if (reductionRatio < 1) { - radii.setWidth(reductionRatio * radii.width()); - radii.setHeight(reductionRatio * radii.height()); - } -} - -PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutSize& logicalBoxSize, WritingMode writingMode, Length margin, Length padding) +PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutSize& logicalBoxSize, WritingMode writingMode, float margin) { ASSERT(basicShape); bool horizontalWritingMode = isHorizontalWritingMode(writingMode); - float boxWidth = horizontalWritingMode ? logicalBoxSize.width() : logicalBoxSize.height(); - float boxHeight = horizontalWritingMode ? logicalBoxSize.height() : logicalBoxSize.width(); + float boxWidth = horizontalWritingMode ? logicalBoxSize.width().toFloat() : logicalBoxSize.height().toFloat(); + float boxHeight = horizontalWritingMode ? logicalBoxSize.height().toFloat() : logicalBoxSize.width().toFloat(); OwnPtr<Shape> shape; switch (basicShape->type()) { - case BasicShape::BasicShapeRectangleType: { - const BasicShapeRectangle* rectangle = static_cast<const BasicShapeRectangle*>(basicShape); - FloatRect bounds( - floatValueForLength(rectangle->x(), boxWidth), - floatValueForLength(rectangle->y(), boxHeight), - floatValueForLength(rectangle->width(), boxWidth), - floatValueForLength(rectangle->height(), boxHeight)); - FloatSize cornerRadii( - floatValueForLength(rectangle->cornerRadiusX(), boxWidth), - floatValueForLength(rectangle->cornerRadiusY(), boxHeight)); - ensureRadiiDoNotOverlap(bounds, cornerRadii); - FloatRect logicalBounds = physicalRectToLogical(bounds, logicalBoxSize.height(), writingMode); - - shape = createRectangleShape(logicalBounds, physicalSizeToLogical(cornerRadii, writingMode)); - break; - } - case BasicShape::BasicShapeCircleType: { const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(basicShape); - float centerX = floatValueForLength(circle->centerX(), boxWidth); - float centerY = floatValueForLength(circle->centerY(), boxHeight); - // This method of computing the radius is as defined in SVG - // (http://www.w3.org/TR/SVG/coords.html#Units). It bases the radius - // off of the diagonal of the box and ensures that if the box is - // square, the radius is equal to half the diagonal. - float radius = floatValueForLength(circle->radius(), sqrtf((boxWidth * boxWidth + boxHeight * boxHeight) / 2)); - FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode); + FloatPoint center = floatPointForCenterCoordinate(circle->centerX(), circle->centerY(), FloatSize(boxWidth, boxHeight)); + float radius = circle->floatValueForRadiusInBox(FloatSize(boxWidth, boxHeight)); + FloatPoint logicalCenter = physicalPointToLogical(center, logicalBoxSize.height().toFloat(), writingMode); shape = createCircleShape(logicalCenter, radius); break; @@ -155,14 +118,12 @@ PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutS case BasicShape::BasicShapeEllipseType: { const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(basicShape); - float centerX = floatValueForLength(ellipse->centerX(), boxWidth); - float centerY = floatValueForLength(ellipse->centerY(), boxHeight); - float radiusX = floatValueForLength(ellipse->radiusX(), boxWidth); - float radiusY = floatValueForLength(ellipse->radiusY(), boxHeight); - FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode); - FloatSize logicalRadii = physicalSizeToLogical(FloatSize(radiusX, radiusY), writingMode); - - shape = createEllipseShape(logicalCenter, logicalRadii); + FloatPoint center = floatPointForCenterCoordinate(ellipse->centerX(), ellipse->centerY(), FloatSize(boxWidth, boxHeight)); + float radiusX = ellipse->floatValueForRadiusInBox(ellipse->radiusX(), center.x(), boxWidth); + float radiusY = ellipse->floatValueForRadiusInBox(ellipse->radiusY(), center.y(), boxHeight); + FloatPoint logicalCenter = physicalPointToLogical(center, logicalBoxSize.height().toFloat(), writingMode); + + shape = createEllipseShape(logicalCenter, FloatSize(radiusX, radiusY)); break; } @@ -176,28 +137,31 @@ PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutS FloatPoint vertex( floatValueForLength(values.at(i), boxWidth), floatValueForLength(values.at(i + 1), boxHeight)); - (*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxSize.height(), writingMode); + (*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxSize.height().toFloat(), writingMode); } shape = createPolygonShape(vertices.release(), polygon->windRule()); break; } - case BasicShape::BasicShapeInsetRectangleType: { - const BasicShapeInsetRectangle* rectangle = static_cast<const BasicShapeInsetRectangle*>(basicShape); - float left = floatValueForLength(rectangle->left(), boxWidth); - float top = floatValueForLength(rectangle->top(), boxHeight); - FloatRect bounds( - left, - top, - boxWidth - left - floatValueForLength(rectangle->right(), boxWidth), - boxHeight - top - floatValueForLength(rectangle->bottom(), boxHeight)); - FloatSize cornerRadii( - floatValueForLength(rectangle->cornerRadiusX(), boxWidth), - floatValueForLength(rectangle->cornerRadiusY(), boxHeight)); - ensureRadiiDoNotOverlap(bounds, cornerRadii); - FloatRect logicalBounds = physicalRectToLogical(bounds, logicalBoxSize.height(), writingMode); - - shape = createRectangleShape(logicalBounds, physicalSizeToLogical(cornerRadii, writingMode)); + case BasicShape::BasicShapeInsetType: { + const BasicShapeInset& inset = *static_cast<const BasicShapeInset*>(basicShape); + float left = floatValueForLength(inset.left(), boxWidth); + float top = floatValueForLength(inset.top(), boxHeight); + float right = floatValueForLength(inset.right(), boxWidth); + float bottom = floatValueForLength(inset.bottom(), boxHeight); + FloatRect rect(left, top, std::max<float>(boxWidth - left - right, 0), std::max<float>(boxHeight - top - bottom, 0)); + FloatRect logicalRect = physicalRectToLogical(rect, logicalBoxSize.height().toFloat(), writingMode); + + FloatSize boxSize(boxWidth, boxHeight); + FloatSize topLeftRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.topLeftRadius(), boxSize), writingMode); + FloatSize topRightRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.topRightRadius(), boxSize), writingMode); + FloatSize bottomLeftRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.bottomLeftRadius(), boxSize), writingMode); + FloatSize bottomRightRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.bottomRightRadius(), boxSize), writingMode); + FloatRoundedRect::Radii cornerRadii(topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); + + cornerRadii.scale(calcBorderRadiiConstraintScaleFor(logicalRect, cornerRadii)); + + shape = createInsetShape(FloatRoundedRect(logicalRect, cornerRadii)); break; } @@ -206,61 +170,60 @@ PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutS } shape->m_writingMode = writingMode; - shape->m_margin = floatValueForLength(margin, 0); - shape->m_padding = floatValueForLength(padding, 0); + shape->m_margin = margin; return shape.release(); } -PassOwnPtr<Shape> Shape::createShape(const StyleImage* styleImage, float threshold, const LayoutSize&, WritingMode writingMode, Length margin, Length padding) +PassOwnPtr<Shape> Shape::createRasterShape(Image* image, float threshold, const LayoutRect& imageR, const LayoutRect& marginR, WritingMode writingMode, float margin) { - ASSERT(styleImage && styleImage->isImageResource() && styleImage->cachedImage() && styleImage->cachedImage()->image()); + IntRect imageRect = pixelSnappedIntRect(imageR); + IntRect marginRect = pixelSnappedIntRect(marginR); + OwnPtr<RasterShapeIntervals> intervals = adoptPtr(new RasterShapeIntervals(marginRect.height(), -marginRect.y())); + OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(imageRect.size()); - Image* image = styleImage->cachedImage()->image(); - const IntSize& imageSize = image->size(); - OwnPtr<RasterShapeIntervals> intervals = adoptPtr(new RasterShapeIntervals(imageSize.height())); - OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(imageSize); if (imageBuffer) { GraphicsContext* graphicsContext = imageBuffer->context(); - graphicsContext->drawImage(image, IntPoint()); + graphicsContext->drawImage(image, IntRect(IntPoint(), imageRect.size())); - RefPtr<Uint8ClampedArray> pixelArray = imageBuffer->getUnmultipliedImageData(IntRect(IntPoint(), imageSize)); - unsigned pixelArrayLength = pixelArray->length(); + RefPtr<Uint8ClampedArray> pixelArray = imageBuffer->getUnmultipliedImageData(IntRect(IntPoint(), imageRect.size())); unsigned pixelArrayOffset = 3; // Each pixel is four bytes: RGBA. uint8_t alphaPixelThreshold = threshold * 255; - ASSERT(static_cast<unsigned>(imageSize.width() * imageSize.height() * 4) == pixelArrayLength); + ASSERT(static_cast<unsigned>(imageRect.width() * imageRect.height() * 4) == pixelArray->length()); + + int minBufferY = std::max(0, marginRect.y() - imageRect.y()); + int maxBufferY = std::min(imageRect.height(), marginRect.maxY() - imageRect.y()); - for (int y = 0; y < imageSize.height(); ++y) { + for (int y = minBufferY; y < maxBufferY; ++y) { int startX = -1; - for (int x = 0; x < imageSize.width() && pixelArrayOffset < pixelArrayLength; ++x, pixelArrayOffset += 4) { + for (int x = 0; x < imageRect.width(); ++x, pixelArrayOffset += 4) { uint8_t alpha = pixelArray->item(pixelArrayOffset); - if ((startX == -1) && alpha > alphaPixelThreshold) { + bool alphaAboveThreshold = alpha > alphaPixelThreshold; + if (startX == -1 && alphaAboveThreshold) { startX = x; - } else if (startX != -1 && (alpha <= alphaPixelThreshold || x == imageSize.width() - 1)) { - intervals->appendInterval(y, startX, x); + } else if (startX != -1 && (!alphaAboveThreshold || x == imageRect.width() - 1)) { + int endX = alphaAboveThreshold ? x + 1 : x; + intervals->intervalAt(y + imageRect.y()).unite(IntShapeInterval(startX + imageRect.x(), endX + imageRect.x())); startX = -1; } } } } - OwnPtr<RasterShape> rasterShape = adoptPtr(new RasterShape(intervals.release(), imageSize)); + OwnPtr<RasterShape> rasterShape = adoptPtr(new RasterShape(intervals.release(), marginRect.size())); rasterShape->m_writingMode = writingMode; - rasterShape->m_margin = floatValueForLength(margin, 0); - rasterShape->m_padding = floatValueForLength(padding, 0); + rasterShape->m_margin = margin; return rasterShape.release(); } -PassOwnPtr<Shape> Shape::createLayoutBoxShape(const LayoutSize& logicalSize, WritingMode writingMode, const Length& margin, const Length& padding) +PassOwnPtr<Shape> Shape::createLayoutBoxShape(const RoundedRect& roundedRect, WritingMode writingMode, float margin) { - FloatRect rect(0, 0, logicalSize.width(), logicalSize.height()); - FloatSize radii(0, 0); - FloatRoundedRect bounds(rect, radii, radii, radii, radii); - OwnPtr<Shape> shape = createBoxShape(bounds); + FloatRect rect(0, 0, roundedRect.rect().width(), roundedRect.rect().height()); + FloatRoundedRect bounds(rect, roundedRect.radii()); + OwnPtr<Shape> shape = createInsetShape(bounds); shape->m_writingMode = writingMode; - shape->m_margin = floatValueForLength(margin, 0); - shape->m_padding = floatValueForLength(padding, 0); + shape->m_margin = margin; return shape.release(); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/Shape.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/Shape.h index de9aef9f99d..fb649957671 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/Shape.h +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/Shape.h @@ -33,6 +33,8 @@ #include "core/rendering/style/BasicShapes.h" #include "core/rendering/style/StyleImage.h" #include "platform/geometry/LayoutRect.h" +#include "platform/geometry/RoundedRect.h" +#include "platform/graphics/Path.h" #include "platform/text/WritingMode.h" #include "wtf/PassOwnPtr.h" #include "wtf/Vector.h" @@ -60,24 +62,25 @@ typedef Vector<LineSegment> SegmentList; class Shape { public: - static PassOwnPtr<Shape> createShape(const BasicShape*, const LayoutSize& logicalBoxSize, WritingMode, Length margin, Length padding); - static PassOwnPtr<Shape> createShape(const StyleImage*, float threshold, const LayoutSize& logicalBoxSize, WritingMode, Length margin, Length padding); - static PassOwnPtr<Shape> createLayoutBoxShape(const LayoutSize& logicalBoxSize, WritingMode, const Length& margin, const Length& padding); + struct DisplayPaths { + Path shape; + Path marginShape; + }; + static PassOwnPtr<Shape> createShape(const BasicShape*, const LayoutSize& logicalBoxSize, WritingMode, float margin); + static PassOwnPtr<Shape> createRasterShape(Image*, float threshold, const LayoutRect& imageRect, const LayoutRect& marginRect, WritingMode, float margin); + static PassOwnPtr<Shape> createLayoutBoxShape(const RoundedRect&, WritingMode, float margin); virtual ~Shape() { } virtual LayoutRect shapeMarginLogicalBoundingBox() const = 0; - virtual LayoutRect shapePaddingLogicalBoundingBox() const = 0; virtual bool isEmpty() const = 0; - virtual void getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const = 0; virtual void getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const = 0; - virtual bool firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit& result) const = 0; + bool lineOverlapsShapeMarginBounds(LayoutUnit lineTop, LayoutUnit lineHeight) const { return lineOverlapsBoundingBox(lineTop, lineHeight, shapeMarginLogicalBoundingBox()); } - bool lineOverlapsShapePaddingBounds(LayoutUnit lineTop, LayoutUnit lineHeight) const { return lineOverlapsBoundingBox(lineTop, lineHeight, shapePaddingLogicalBoundingBox()); } + virtual void buildDisplayPaths(DisplayPaths&) const = 0; protected: float shapeMargin() const { return m_margin; } - float shapePadding() const { return m_padding; } private: bool lineOverlapsBoundingBox(LayoutUnit lineTop, LayoutUnit lineHeight, const LayoutRect& rect) const @@ -89,7 +92,6 @@ private: WritingMode m_writingMode; float m_margin; - float m_padding; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInfo.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInfo.cpp deleted file mode 100644 index e2668712991..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInfo.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 "core/rendering/shapes/ShapeInfo.h" - -#include "core/rendering/RenderRegion.h" - -namespace WebCore { - -bool checkShapeImageOrigin(Document& document, ImageResource& imageResource) -{ - if (imageResource.isAccessAllowed(document.securityOrigin())) - return true; - - const KURL& url = imageResource.url(); - String urlString = url.isNull() ? "''" : url.elidedString(); - document.addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Unsafe attempt to load URL " + urlString + "."); - - return false; -} - -template<class RenderType> -const Shape* ShapeInfo<RenderType>::computedShape() const -{ - if (Shape* shape = m_shape.get()) - return shape; - - WritingMode writingMode = m_renderer->style()->writingMode(); - Length margin = m_renderer->style()->shapeMargin(); - Length padding = m_renderer->style()->shapePadding(); - float shapeImageThreshold = m_renderer->style()->shapeImageThreshold(); - const ShapeValue* shapeValue = this->shapeValue(); - ASSERT(shapeValue); - - switch (shapeValue->type()) { - case ShapeValue::Shape: - ASSERT(shapeValue->shape()); - m_shape = Shape::createShape(shapeValue->shape(), m_shapeLogicalSize, writingMode, margin, padding); - break; - case ShapeValue::Image: - ASSERT(shapeValue->image()); - m_shape = Shape::createShape(shapeValue->image(), shapeImageThreshold, m_shapeLogicalSize, writingMode, margin, padding); - break; - case ShapeValue::Box: - m_shape = Shape::createLayoutBoxShape(m_shapeLogicalSize, writingMode, margin, padding); - break; - case ShapeValue::Outside: - // Outside should have already resolved to a different shape value. - ASSERT_NOT_REACHED(); - } - - ASSERT(m_shape); - return m_shape.get(); -} - -template<class RenderType> -SegmentList ShapeInfo<RenderType>::computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight) const -{ - ASSERT(lineHeight >= 0); - SegmentList segments; - - getIntervals((lineTop - logicalTopOffset()), std::min(lineHeight, shapeLogicalBottom() - lineTop), segments); - - for (size_t i = 0; i < segments.size(); i++) { - segments[i].logicalLeft += logicalLeftOffset(); - segments[i].logicalRight += logicalLeftOffset(); - } - - return segments; -} - -template class ShapeInfo<RenderBlock>; -template class ShapeInfo<RenderBox>; -} diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInfo.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInfo.h deleted file mode 100644 index 1314f3409c1..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInfo.h +++ /dev/null @@ -1,179 +0,0 @@ -/* -* 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 ShapeInfo_h -#define ShapeInfo_h - -#include "core/rendering/shapes/Shape.h" -#include "core/rendering/style/RenderStyle.h" -#include "core/rendering/style/ShapeValue.h" -#include "platform/LayoutUnit.h" -#include "platform/geometry/FloatRect.h" -#include "wtf/OwnPtr.h" -#include "wtf/Vector.h" - -namespace WebCore { - -template<class KeyType, class InfoType> -class MappedInfo { -public: - static InfoType* ensureInfo(const KeyType* key) - { - InfoMap& infoMap = MappedInfo<KeyType, InfoType>::infoMap(); - if (InfoType* info = infoMap.get(key)) - return info; - typename InfoMap::AddResult result = infoMap.add(key, InfoType::createInfo(key)); - return result.iterator->value.get(); - } - static void removeInfo(const KeyType* key) { infoMap().remove(key); } - static InfoType* info(const KeyType* key) { return infoMap().get(key); } -private: - typedef HashMap<const KeyType*, OwnPtr<InfoType> > InfoMap; - static InfoMap& infoMap() - { - DEFINE_STATIC_LOCAL(InfoMap, staticInfoMap, ()); - return staticInfoMap; - } -}; - -template<class RenderType> -class ShapeInfo { - WTF_MAKE_FAST_ALLOCATED; -public: - virtual ~ShapeInfo() { } - - void setShapeSize(LayoutUnit logicalWidth, LayoutUnit logicalHeight) - { - if (shapeValue()->type() == ShapeValue::Box) { - switch (shapeValue()->layoutBox()) { - case MarginBox: - logicalHeight += m_renderer->marginLogicalHeight(); - logicalWidth += m_renderer->marginLogicalWidth(); - break; - case BorderBox: - break; - case PaddingBox: - logicalHeight -= m_renderer->borderLogicalHeight(); - logicalWidth -= m_renderer->borderLogicalWidth(); - break; - case ContentBox: - logicalHeight -= m_renderer->borderAndPaddingLogicalHeight(); - logicalWidth -= m_renderer->borderAndPaddingLogicalWidth(); - break; - } - } else if (m_renderer->style()->boxSizing() == CONTENT_BOX) { - logicalHeight -= m_renderer->borderAndPaddingLogicalHeight(); - logicalWidth -= m_renderer->borderAndPaddingLogicalWidth(); - } - - LayoutSize newLogicalSize(logicalWidth, logicalHeight); - if (m_shapeLogicalSize == newLogicalSize) - return; - dirtyShapeSize(); - m_shapeLogicalSize = newLogicalSize; - } - - SegmentList computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight) const; - - LayoutUnit shapeLogicalTop() const { return computedShapeLogicalBoundingBox().y() + logicalTopOffset(); } - LayoutUnit shapeLogicalBottom() const { return computedShapeLogicalBoundingBox().maxY() + logicalTopOffset(); } - LayoutUnit shapeLogicalLeft() const { return computedShapeLogicalBoundingBox().x() + logicalLeftOffset(); } - LayoutUnit shapeLogicalRight() const { return computedShapeLogicalBoundingBox().maxX() + logicalLeftOffset(); } - LayoutUnit shapeLogicalWidth() const { return computedShapeLogicalBoundingBox().width(); } - LayoutUnit shapeLogicalHeight() const { return computedShapeLogicalBoundingBox().height(); } - - LayoutUnit logicalLineTop() const { return m_shapeLineTop + logicalTopOffset(); } - LayoutUnit logicalLineBottom() const { return m_shapeLineTop + m_lineHeight + logicalTopOffset(); } - - LayoutUnit shapeContainingBlockHeight() const { return (m_renderer->style()->boxSizing() == CONTENT_BOX) ? (m_shapeLogicalSize.height() + m_renderer->borderAndPaddingLogicalHeight()) : m_shapeLogicalSize.height(); } - - virtual bool lineOverlapsShapeBounds() const = 0; - - void dirtyShapeSize() { m_shape.clear(); } - bool shapeSizeDirty() { return !m_shape.get(); } - const RenderType* owner() const { return m_renderer; } - LayoutSize shapeSize() const { return m_shapeLogicalSize; } - -protected: - ShapeInfo(const RenderType* renderer): m_renderer(renderer) { } - - const Shape* computedShape() const; - - virtual LayoutRect computedShapeLogicalBoundingBox() const = 0; - virtual ShapeValue* shapeValue() const = 0; - virtual void getIntervals(LayoutUnit, LayoutUnit, SegmentList&) const = 0; - - LayoutUnit logicalTopOffset() const - { - if (shapeValue()->type() == ShapeValue::Box) { - switch (shapeValue()->layoutBox()) { - case MarginBox: - return -m_renderer->marginBefore(); - case BorderBox: - return LayoutUnit(); - case PaddingBox: - return m_renderer->borderBefore(); - case ContentBox: - return m_renderer->borderAndPaddingBefore(); - } - } - return m_renderer->style()->boxSizing() == CONTENT_BOX ? m_renderer->borderAndPaddingBefore() : LayoutUnit(); - } - - LayoutUnit logicalLeftOffset() const - { - if (shapeValue()->type() == ShapeValue::Box) { - switch (shapeValue()->layoutBox()) { - case MarginBox: - return -m_renderer->marginStart(); - case BorderBox: - return LayoutUnit(); - case PaddingBox: - return m_renderer->borderStart(); - case ContentBox: - return m_renderer->borderAndPaddingStart(); - } - } - return (m_renderer->style()->boxSizing() == CONTENT_BOX && !m_renderer->isRenderRegion()) ? m_renderer->borderAndPaddingStart() : LayoutUnit(); - } - - LayoutUnit m_shapeLineTop; - LayoutUnit m_lineHeight; - - const RenderType* m_renderer; - -private: - mutable OwnPtr<Shape> m_shape; - LayoutSize m_shapeLogicalSize; -}; - -bool checkShapeImageOrigin(Document&, ImageResource&); - -} -#endif diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInsideInfo.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInsideInfo.cpp deleted file mode 100644 index 301200b19e7..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInsideInfo.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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 "core/rendering/shapes/ShapeInsideInfo.h" - -#include "core/rendering/InlineIterator.h" -#include "core/rendering/RenderBlock.h" - -namespace WebCore { - -LineSegmentRange::LineSegmentRange(const InlineIterator& start, const InlineIterator& end) - : start(start.root(), start.object(), start.offset()) - , end(end.root(), end.object(), end.offset()) - { - } - -bool ShapeInsideInfo::isEnabledFor(const RenderBlock* renderer) -{ - ShapeValue* shapeValue = renderer->style()->resolvedShapeInside(); - if (!shapeValue) - return false; - - switch (shapeValue->type()) { - case ShapeValue::Shape: - return shapeValue->shape() && shapeValue->shape()->type() != BasicShape::BasicShapeInsetRectangleType; - case ShapeValue::Image: - return shapeValue->isImageValid() && checkShapeImageOrigin(renderer->document(), *(shapeValue->image()->cachedImage())); - case ShapeValue::Box: - case ShapeValue::Outside: - return false; - } - - return false; -} - -bool ShapeInsideInfo::updateSegmentsForLine(LayoutSize lineOffset, LayoutUnit lineHeight) -{ - bool result = updateSegmentsForLine(lineOffset.height(), lineHeight); - for (size_t i = 0; i < m_segments.size(); i++) { - m_segments[i].logicalLeft -= lineOffset.width(); - m_segments[i].logicalRight -= lineOffset.width(); - } - return result; -} - -bool ShapeInsideInfo::updateSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight) -{ - ASSERT(lineHeight >= 0); - m_shapeLineTop = lineTop - logicalTopOffset(); - m_lineHeight = lineHeight; - m_segments.clear(); - m_segmentRanges.clear(); - - if (lineOverlapsShapeBounds()) - m_segments = computeSegmentsForLine(lineTop, lineHeight); - - return m_segments.size(); -} - -bool ShapeInsideInfo::adjustLogicalLineTop(float minSegmentWidth) -{ - const Shape* shape = computedShape(); - if (!shape || m_lineHeight <= 0 || logicalLineTop() > shapeLogicalBottom()) - return false; - - LayoutUnit newLineTop; - if (shape->firstIncludedIntervalLogicalTop(m_shapeLineTop, LayoutSize(minSegmentWidth, m_lineHeight), newLineTop)) { - if (newLineTop > m_shapeLineTop) { - m_shapeLineTop = newLineTop; - return true; - } - } - - return false; -} - -ShapeValue* ShapeInsideInfo::shapeValue() const -{ - return m_renderer->style()->resolvedShapeInside(); -} - -LayoutUnit ShapeInsideInfo::computeFirstFitPositionForFloat(const LayoutSize floatSize) const -{ - if (!computedShape() || !floatSize.width() || shapeLogicalBottom() < logicalLineTop()) - return 0; - - LayoutUnit firstFitPosition = 0; - if (computedShape()->firstIncludedIntervalLogicalTop(m_shapeLineTop, floatSize, firstFitPosition) && (m_shapeLineTop <= firstFitPosition)) - return firstFitPosition; - - return 0; -} - -} diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInsideInfo.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInsideInfo.h deleted file mode 100644 index 0f0f3855266..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInsideInfo.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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 ShapeInsideInfo_h -#define ShapeInsideInfo_h - -#include "core/rendering/shapes/ShapeInfo.h" -#include "wtf/PassOwnPtr.h" -#include "wtf/Vector.h" - -namespace WebCore { - -class InlineIterator; -class RenderBlock; -class RenderObject; - -struct LineSegmentIterator { - RenderObject* root; - RenderObject* object; - unsigned offset; - LineSegmentIterator(RenderObject* root, RenderObject* object, unsigned offset) - : root(root) - , object(object) - , offset(offset) - { - } -}; - -struct LineSegmentRange { - LineSegmentIterator start; - LineSegmentIterator end; - LineSegmentRange(const InlineIterator& start, const InlineIterator& end); -}; - -typedef Vector<LineSegmentRange> SegmentRangeList; - -class ShapeInsideInfo FINAL : public ShapeInfo<RenderBlock> { -public: - static PassOwnPtr<ShapeInsideInfo> createInfo(const RenderBlock* renderer) { return adoptPtr(new ShapeInsideInfo(renderer)); } - - static bool isEnabledFor(const RenderBlock* renderer); - - bool updateSegmentsForLine(LayoutSize lineOffset, LayoutUnit lineHeight); - bool updateSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight); - - bool hasSegments() const - { - return lineOverlapsShapeBounds() && m_segments.size(); - } - const SegmentList& segments() const - { - ASSERT(hasSegments()); - return m_segments; - } - SegmentRangeList& segmentRanges() { return m_segmentRanges; } - const SegmentRangeList& segmentRanges() const { return m_segmentRanges; } - const LineSegment* currentSegment() const - { - if (!hasSegments()) - return 0; - ASSERT(m_segmentRanges.size() < m_segments.size()); - return &m_segments[m_segmentRanges.size()]; - } - void clearSegments() { m_segments.clear(); } - bool adjustLogicalLineTop(float minSegmentWidth); - LayoutUnit computeFirstFitPositionForFloat(const LayoutSize) const; - - void setNeedsLayout(bool value) { m_needsLayout = value; } - bool needsLayout() { return m_needsLayout; } - - virtual bool lineOverlapsShapeBounds() const OVERRIDE - { - return computedShape()->lineOverlapsShapePaddingBounds(m_shapeLineTop, m_lineHeight); - } - -protected: - virtual LayoutRect computedShapeLogicalBoundingBox() const OVERRIDE { return computedShape()->shapePaddingLogicalBoundingBox(); } - virtual ShapeValue* shapeValue() const OVERRIDE; - virtual void getIntervals(LayoutUnit lineTop, LayoutUnit lineHeight, SegmentList& segments) const OVERRIDE - { - return computedShape()->getIncludedIntervals(lineTop, lineHeight, segments); - } - -private: - ShapeInsideInfo(const RenderBlock* renderer) - : ShapeInfo<RenderBlock> (renderer) - , m_needsLayout(false) - { } - - SegmentRangeList m_segmentRanges; - bool m_needsLayout; - SegmentList m_segments; -}; - -} -#endif diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInterval.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInterval.h index efeb7d862c0..47c20178f0f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInterval.h +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInterval.h @@ -38,29 +38,27 @@ template <typename T> class ShapeInterval { WTF_MAKE_FAST_ALLOCATED; public: - ShapeInterval(T x1 = 0, T x2 = 0) - : m_x1(x1) - , m_x2(x2) + ShapeInterval() + : m_x1(-1) + , m_x2(-2) { - ASSERT(x2 >= x1); + // The initial values of m_x1,x2 don't matter (unless you're looking + // at them in the debugger) so long as isUndefined() is true. + ASSERT(isUndefined()); } - T x1() const { return m_x1; } - T x2() const { return m_x2; } - T width() const { return m_x2 - m_x1; } - bool isEmpty() const { return m_x1 == m_x2; } - - void setX1(T x1) + ShapeInterval(T x1, T x2) + : m_x1(x1) + , m_x2(x2) { - ASSERT(m_x2 >= x1); - m_x1 = x1; + ASSERT(x2 >= x1); } - void setX2(T x2) - { - ASSERT(x2 >= m_x1); - m_x2 = x2; - } + bool isUndefined() const { return m_x2 < m_x1; } + T x1() const { return isUndefined() ? 0 : m_x1; } + T x2() const { return isUndefined() ? 0 : m_x2; } + T width() const { return isUndefined() ? 0 : m_x2 - m_x1; } + bool isEmpty() const { return isUndefined() ? true : m_x1 == m_x2; } void set(T x1, T x2) { @@ -71,155 +69,34 @@ public: bool overlaps(const ShapeInterval<T>& interval) const { + if (isUndefined() || interval.isUndefined()) + return false; return x2() >= interval.x1() && x1() <= interval.x2(); } bool contains(const ShapeInterval<T>& interval) const { + if (isUndefined() || interval.isUndefined()) + return false; return x1() <= interval.x1() && x2() >= interval.x2(); } - ShapeInterval<T> intersect(const ShapeInterval<T>& interval) const - { - ASSERT(overlaps(interval)); - return ShapeInterval<T>(std::max<T>(x1(), interval.x1()), std::min<T>(x2(), interval.x2())); - } - - typedef Vector<ShapeInterval<T> > ShapeIntervals; - typedef typename ShapeIntervals::const_iterator const_iterator; - typedef typename ShapeIntervals::iterator iterator; - - static void uniteShapeIntervals(const ShapeIntervals& a, const ShapeIntervals& b, ShapeIntervals& result) - { - ASSERT(shapeIntervalsAreSortedAndDisjoint(a) && shapeIntervalsAreSortedAndDisjoint(b)); - - if (a.isEmpty() || a == b) { - result.appendRange(b.begin(), b.end()); - return; - } - - if (b.isEmpty()) { - result.appendRange(a.begin(), a.end()); - return; - } - - const_iterator aNext = a.begin(); - const_iterator bNext = b.begin(); - - while (aNext != a.end() || bNext != b.end()) { - const_iterator next = (bNext == b.end() || (aNext != a.end() && aNext->x1() < bNext->x1())) ? aNext++ : bNext++; - if (result.isEmpty() || !result.last().overlaps(*next)) - result.append(*next); - else - result.last().setX2(std::max<T>(result.last().x2(), next->x2())); - } - } - - static void intersectShapeIntervals(const ShapeIntervals& a, const ShapeIntervals& b, ShapeIntervals& result) - { - ASSERT(shapeIntervalsAreSortedAndDisjoint(a) && shapeIntervalsAreSortedAndDisjoint(b)); - - if (a.isEmpty() || b.isEmpty()) - return; - - if (a == b) { - result.appendRange(a.begin(), a.end()); - return; - } - - const_iterator aNext = a.begin(); - const_iterator bNext = b.begin(); - const_iterator working = aNext->x1() < bNext->x1() ? aNext++ : bNext++; - - while (aNext != a.end() || bNext != b.end()) { - const_iterator next = (bNext == b.end() || (aNext != a.end() && aNext->x1() < bNext->x1())) ? aNext++ : bNext++; - if (working->overlaps(*next)) { - result.append(working->intersect(*next)); - if (next->x2() > working->x2()) - working = next; - } else { - working = next; - } - } - } + bool operator==(const ShapeInterval<T>& other) const { return x1() == other.x1() && x2() == other.x2(); } + bool operator!=(const ShapeInterval<T>& other) const { return !operator==(other); } - static void subtractShapeIntervals(const ShapeIntervals& a, const ShapeIntervals& b, ShapeIntervals& result) + void unite(const ShapeInterval<T>& interval) { - ASSERT(shapeIntervalsAreSortedAndDisjoint(a) && shapeIntervalsAreSortedAndDisjoint(b)); - - if (a.isEmpty() || a == b) - return; - - if (b.isEmpty()) { - result.appendRange(a.begin(), a.end()); + if (interval.isUndefined()) return; - } - - const_iterator aNext = a.begin(); - const_iterator bNext = b.begin(); - ShapeInterval<T> aValue = *aNext; - ShapeInterval<T> bValue = *bNext; - - do { - bool aIncrement = false; - bool bIncrement = false; - - if (bValue.contains(aValue)) { - aIncrement = true; - } else if (aValue.contains(bValue)) { - if (bValue.x1() > aValue.x1()) - result.append(ShapeInterval<T>(aValue.x1(), bValue.x1())); - if (aValue.x2() > bValue.x2()) - aValue.setX1(bValue.x2()); - else - aIncrement = true; - bIncrement = true; - } else if (aValue.overlaps(bValue)) { - if (aValue.x1() < bValue.x1()) { - result.append(ShapeInterval<T>(aValue.x1(), bValue.x1())); - aIncrement = true; - } else { - aValue.setX1(bValue.x2()); - bIncrement = true; - } - } else { - if (aValue.x1() < bValue.x1()) { - result.append(aValue); - aIncrement = true; - } else { - bIncrement = true; - } - } - - if (aIncrement && ++aNext != a.end()) - aValue = *aNext; - if (bIncrement && ++bNext != b.end()) - bValue = *bNext; - - } while (aNext != a.end() && bNext != b.end()); - - if (aNext != a.end()) { - result.append(aValue); - result.appendRange(++aNext, a.end()); - } + if (isUndefined()) + set(interval.x1(), interval.x2()); + else + set(std::min<T>(x1(), interval.x1()), std::max<T>(x2(), interval.x2())); } - bool operator==(const ShapeInterval<T>& other) const { return x1() == other.x1() && x2() == other.x2(); } - bool operator!=(const ShapeInterval<T>& other) const { return !operator==(other); } - private: T m_x1; T m_x2; - - static bool shapeIntervalsAreSortedAndDisjoint(const ShapeIntervals& intervals) - { - for (unsigned i = 1; i < intervals.size(); i++) { - if (intervals[i - 1].x2() > intervals[i].x1()) - return false; - } - - return true; - } }; typedef ShapeInterval<int> IntShapeInterval; diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.cpp index 98bea9a0a16..216d3091acf 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.cpp @@ -33,48 +33,269 @@ #include "core/rendering/FloatingObjects.h" #include "core/rendering/RenderBlockFlow.h" #include "core/rendering/RenderBox.h" +#include "core/rendering/RenderImage.h" +#include "platform/LengthFunctions.h" namespace WebCore { -bool ShapeOutsideInfo::isEnabledFor(const RenderBox* box) + +CSSBoxType referenceBox(const ShapeValue& shapeValue) +{ + if (shapeValue.cssBox() == BoxMissing) + return MarginBox; + return shapeValue.cssBox(); +} + +void ShapeOutsideInfo::setReferenceBoxLogicalSize(LayoutSize newReferenceBoxLogicalSize) +{ + bool isHorizontalWritingMode = m_renderer.containingBlock()->style()->isHorizontalWritingMode(); + switch (referenceBox(*m_renderer.style()->shapeOutside())) { + case MarginBox: + if (isHorizontalWritingMode) + newReferenceBoxLogicalSize.expand(m_renderer.marginWidth(), m_renderer.marginHeight()); + else + newReferenceBoxLogicalSize.expand(m_renderer.marginHeight(), m_renderer.marginWidth()); + break; + case BorderBox: + break; + case PaddingBox: + if (isHorizontalWritingMode) + newReferenceBoxLogicalSize.shrink(m_renderer.borderWidth(), m_renderer.borderHeight()); + else + newReferenceBoxLogicalSize.shrink(m_renderer.borderHeight(), m_renderer.borderWidth()); + break; + case ContentBox: + if (isHorizontalWritingMode) + newReferenceBoxLogicalSize.shrink(m_renderer.borderAndPaddingWidth(), m_renderer.borderAndPaddingHeight()); + else + newReferenceBoxLogicalSize.shrink(m_renderer.borderAndPaddingHeight(), m_renderer.borderAndPaddingWidth()); + break; + case BoxMissing: + ASSERT_NOT_REACHED(); + break; + } + + if (m_referenceBoxLogicalSize == newReferenceBoxLogicalSize) + return; + markShapeAsDirty(); + m_referenceBoxLogicalSize = newReferenceBoxLogicalSize; +} + +static bool checkShapeImageOrigin(Document& document, const StyleImage& styleImage) { - ShapeValue* shapeValue = box->style()->shapeOutside(); - if (!box->isFloating() || !shapeValue) + if (styleImage.isGeneratedImage()) + return true; + + ASSERT(styleImage.cachedImage()); + ImageResource& imageResource = *(styleImage.cachedImage()); + if (imageResource.isAccessAllowed(document.securityOrigin())) + return true; + + const KURL& url = imageResource.url(); + String urlString = url.isNull() ? "''" : url.elidedString(); + document.addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Unsafe attempt to load URL " + urlString + "."); + + return false; +} + +static LayoutRect getShapeImageMarginRect(const RenderBox& renderBox, const LayoutSize& referenceBoxLogicalSize) +{ + LayoutPoint marginBoxOrigin(-renderBox.marginLogicalLeft() - renderBox.borderAndPaddingLogicalLeft(), -renderBox.marginBefore() - renderBox.borderBefore() - renderBox.paddingBefore()); + LayoutSize marginBoxSizeDelta(renderBox.marginLogicalWidth() + renderBox.borderAndPaddingLogicalWidth(), renderBox.marginLogicalHeight() + renderBox.borderAndPaddingLogicalHeight()); + return LayoutRect(marginBoxOrigin, referenceBoxLogicalSize + marginBoxSizeDelta); +} + +PassOwnPtr<Shape> ShapeOutsideInfo::createShapeForImage(StyleImage* styleImage, float shapeImageThreshold, WritingMode writingMode, float margin) const +{ + const IntSize& imageSize = m_renderer.calculateImageIntrinsicDimensions(styleImage, roundedIntSize(m_referenceBoxLogicalSize), RenderImage::ScaleByEffectiveZoom); + styleImage->setContainerSizeForRenderer(&m_renderer, imageSize, m_renderer.style()->effectiveZoom()); + + const LayoutRect& marginRect = getShapeImageMarginRect(m_renderer, m_referenceBoxLogicalSize); + const LayoutRect& imageRect = (m_renderer.isRenderImage()) + ? toRenderImage(&m_renderer)->replacedContentRect() + : LayoutRect(LayoutPoint(), imageSize); + + ASSERT(!styleImage->isPendingImage()); + RefPtr<Image> image = styleImage->image(const_cast<RenderBox*>(&m_renderer), imageSize); + + return Shape::createRasterShape(image.get(), shapeImageThreshold, imageRect, marginRect, writingMode, margin); +} + +const Shape& ShapeOutsideInfo::computedShape() const +{ + if (Shape* shape = m_shape.get()) + return *shape; + + const RenderStyle& style = *m_renderer.style(); + ASSERT(m_renderer.containingBlock()); + const RenderStyle& containingBlockStyle = *m_renderer.containingBlock()->style(); + + WritingMode writingMode = containingBlockStyle.writingMode(); + LayoutUnit maximumValue = m_renderer.containingBlock() ? m_renderer.containingBlock()->contentWidth() : LayoutUnit(); + float margin = floatValueForLength(m_renderer.style()->shapeMargin(), maximumValue.toFloat()); + + float shapeImageThreshold = style.shapeImageThreshold(); + ASSERT(style.shapeOutside()); + const ShapeValue& shapeValue = *style.shapeOutside(); + + switch (shapeValue.type()) { + case ShapeValue::Shape: + ASSERT(shapeValue.shape()); + m_shape = Shape::createShape(shapeValue.shape(), m_referenceBoxLogicalSize, writingMode, margin); + break; + case ShapeValue::Image: + ASSERT(shapeValue.isImageValid()); + m_shape = createShapeForImage(shapeValue.image(), shapeImageThreshold, writingMode, margin); + break; + case ShapeValue::Box: { + const RoundedRect& shapeRect = style.getRoundedBorderFor(LayoutRect(LayoutPoint(), m_referenceBoxLogicalSize), m_renderer.view()); + m_shape = Shape::createLayoutBoxShape(shapeRect, writingMode, margin); + break; + } + } + + ASSERT(m_shape); + return *m_shape; +} + +SegmentList ShapeOutsideInfo::computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight) const +{ + ASSERT(lineHeight >= 0); + SegmentList segments; + + computedShape().getExcludedIntervals((lineTop - logicalTopOffset()), std::min(lineHeight, shapeLogicalBottom() - lineTop), segments); + + for (size_t i = 0; i < segments.size(); i++) { + segments[i].logicalLeft += logicalLeftOffset(); + segments[i].logicalRight += logicalLeftOffset(); + } + + return segments; +} + +inline LayoutUnit borderBeforeInWritingMode(const RenderBox& renderer, WritingMode writingMode) +{ + switch (writingMode) { + case TopToBottomWritingMode: return renderer.borderTop(); + case BottomToTopWritingMode: return renderer.borderBottom(); + case LeftToRightWritingMode: return renderer.borderLeft(); + case RightToLeftWritingMode: return renderer.borderRight(); + } + + ASSERT_NOT_REACHED(); + return renderer.borderBefore(); +} + +inline LayoutUnit borderAndPaddingBeforeInWritingMode(const RenderBox& renderer, WritingMode writingMode) +{ + switch (writingMode) { + case TopToBottomWritingMode: return renderer.borderTop() + renderer.paddingTop(); + case BottomToTopWritingMode: return renderer.borderBottom() + renderer.paddingBottom(); + case LeftToRightWritingMode: return renderer.borderLeft() + renderer.paddingLeft(); + case RightToLeftWritingMode: return renderer.borderRight() + renderer.paddingRight(); + } + + ASSERT_NOT_REACHED(); + return renderer.borderAndPaddingBefore(); +} + +LayoutUnit ShapeOutsideInfo::logicalTopOffset() const +{ + switch (referenceBox(*m_renderer.style()->shapeOutside())) { + case MarginBox: return -m_renderer.marginBefore(m_renderer.containingBlock()->style()); + case BorderBox: return LayoutUnit(); + case PaddingBox: return borderBeforeInWritingMode(m_renderer, m_renderer.containingBlock()->style()->writingMode()); + case ContentBox: return borderAndPaddingBeforeInWritingMode(m_renderer, m_renderer.containingBlock()->style()->writingMode()); + case BoxMissing: break; + } + + ASSERT_NOT_REACHED(); + return LayoutUnit(); +} + +inline LayoutUnit borderStartWithStyleForWritingMode(const RenderBox& renderer, const RenderStyle* style) +{ + if (style->isHorizontalWritingMode()) { + if (style->isLeftToRightDirection()) + return renderer.borderLeft(); + + return renderer.borderRight(); + } + if (style->isLeftToRightDirection()) + return renderer.borderTop(); + + return renderer.borderBottom(); +} + +inline LayoutUnit borderAndPaddingStartWithStyleForWritingMode(const RenderBox& renderer, const RenderStyle* style) +{ + if (style->isHorizontalWritingMode()) { + if (style->isLeftToRightDirection()) + return renderer.borderLeft() + renderer.paddingLeft(); + + return renderer.borderRight() + renderer.paddingRight(); + } + if (style->isLeftToRightDirection()) + return renderer.borderTop() + renderer.paddingTop(); + + return renderer.borderBottom() + renderer.paddingBottom(); +} + +LayoutUnit ShapeOutsideInfo::logicalLeftOffset() const +{ + switch (referenceBox(*m_renderer.style()->shapeOutside())) { + case MarginBox: return -m_renderer.marginStart(m_renderer.containingBlock()->style()); + case BorderBox: return LayoutUnit(); + case PaddingBox: return borderStartWithStyleForWritingMode(m_renderer, m_renderer.containingBlock()->style()); + case ContentBox: return borderAndPaddingStartWithStyleForWritingMode(m_renderer, m_renderer.containingBlock()->style()); + case BoxMissing: break; + } + + ASSERT_NOT_REACHED(); + return LayoutUnit(); +} + + +bool ShapeOutsideInfo::isEnabledFor(const RenderBox& box) +{ + ShapeValue* shapeValue = box.style()->shapeOutside(); + if (!box.isFloating() || !shapeValue) return false; switch (shapeValue->type()) { case ShapeValue::Shape: return shapeValue->shape(); case ShapeValue::Image: - return shapeValue->isImageValid() && checkShapeImageOrigin(box->document(), *(shapeValue->image()->cachedImage())); + return shapeValue->isImageValid() && checkShapeImageOrigin(box.document(), *(shapeValue->image())); case ShapeValue::Box: return true; - case ShapeValue::Outside: - return false; } return false; } -void ShapeOutsideInfo::updateDeltasForContainingBlockLine(const RenderBlockFlow* containingBlock, const FloatingObject* floatingObject, LayoutUnit lineTop, LayoutUnit lineHeight) +void ShapeOutsideInfo::updateDeltasForContainingBlockLine(const RenderBlockFlow& containingBlock, const FloatingObject& floatingObject, LayoutUnit lineTop, LayoutUnit lineHeight) { - LayoutUnit shapeTop = containingBlock->logicalTopForFloat(floatingObject) + std::max(LayoutUnit(), containingBlock->marginBeforeForChild(m_renderer)); - LayoutUnit floatRelativeLineTop = lineTop - shapeTop; + LayoutUnit borderBoxTop = containingBlock.logicalTopForFloat(&floatingObject) + containingBlock.marginBeforeForChild(&m_renderer); + LayoutUnit borderBoxLineTop = lineTop - borderBoxTop; - if (shapeSizeDirty() || m_lineTop != floatRelativeLineTop || m_lineHeight != lineHeight) { - m_lineTop = floatRelativeLineTop; - m_shapeLineTop = floatRelativeLineTop - logicalTopOffset(); + if (isShapeDirty() || m_borderBoxLineTop != borderBoxLineTop || m_lineHeight != lineHeight) { + m_borderBoxLineTop = borderBoxLineTop; + m_referenceBoxLineTop = borderBoxLineTop - logicalTopOffset(); m_lineHeight = lineHeight; - LayoutUnit floatMarginBoxWidth = containingBlock->logicalWidthForFloat(floatingObject); + LayoutUnit floatMarginBoxWidth = containingBlock.logicalWidthForFloat(&floatingObject); if (lineOverlapsShapeBounds()) { - SegmentList segments = computeSegmentsForLine(floatRelativeLineTop, lineHeight); + SegmentList segments = computeSegmentsForLine(borderBoxLineTop, lineHeight); if (segments.size()) { - LayoutUnit rawLeftMarginBoxDelta = segments.first().logicalLeft + containingBlock->marginStartForChild(m_renderer); - m_leftMarginBoxDelta = clampTo<LayoutUnit>(rawLeftMarginBoxDelta, LayoutUnit(), floatMarginBoxWidth); + LayoutUnit logicalLeftMargin = containingBlock.style()->isLeftToRightDirection() ? containingBlock.marginStartForChild(&m_renderer) : containingBlock.marginEndForChild(&m_renderer); + LayoutUnit rawLeftMarginBoxDelta = segments.first().logicalLeft + logicalLeftMargin; + m_leftMarginBoxDelta = clampToLayoutUnit(rawLeftMarginBoxDelta, LayoutUnit(), floatMarginBoxWidth); - LayoutUnit rawRightMarginBoxDelta = segments.last().logicalRight - containingBlock->logicalWidthForChild(m_renderer) - containingBlock->marginEndForChild(m_renderer); - m_rightMarginBoxDelta = clampTo<LayoutUnit>(rawRightMarginBoxDelta, -floatMarginBoxWidth, LayoutUnit()); + LayoutUnit logicalRightMargin = containingBlock.style()->isLeftToRightDirection() ? containingBlock.marginEndForChild(&m_renderer) : containingBlock.marginStartForChild(&m_renderer); + LayoutUnit rawRightMarginBoxDelta = segments.last().logicalRight - containingBlock.logicalWidthForChild(&m_renderer) - logicalRightMargin; + m_rightMarginBoxDelta = clampToLayoutUnit(rawRightMarginBoxDelta, -floatMarginBoxWidth, LayoutUnit()); + m_lineOverlapsShape = true; return; } } @@ -82,19 +303,45 @@ void ShapeOutsideInfo::updateDeltasForContainingBlockLine(const RenderBlockFlow* // Lines that do not overlap the shape should act as if the float // wasn't there for layout purposes. So we set the deltas to remove the // entire width of the float. - // FIXME: The latest CSS Shapes spec says that in this case, the - // content should interact with previously stacked floats on the line - // as if this outermost float did not exist. Perhaps obviously, this - // solution cannot do that, and will be revisted when that part of the - // spec is implemented. m_leftMarginBoxDelta = floatMarginBoxWidth; m_rightMarginBoxDelta = -floatMarginBoxWidth; + m_lineOverlapsShape = false; } } -ShapeValue* ShapeOutsideInfo::shapeValue() const +LayoutRect ShapeOutsideInfo::computedShapePhysicalBoundingBox() const +{ + LayoutRect physicalBoundingBox = computedShape().shapeMarginLogicalBoundingBox(); + physicalBoundingBox.setX(physicalBoundingBox.x() + logicalLeftOffset()); + + if (m_renderer.style()->isFlippedBlocksWritingMode()) + physicalBoundingBox.setY(m_renderer.logicalHeight() - physicalBoundingBox.maxY()); + else + physicalBoundingBox.setY(physicalBoundingBox.y() + logicalTopOffset()); + + if (!m_renderer.style()->isHorizontalWritingMode()) + physicalBoundingBox = physicalBoundingBox.transposedRect(); + else + physicalBoundingBox.setY(physicalBoundingBox.y() + logicalTopOffset()); + + return physicalBoundingBox; +} + +FloatPoint ShapeOutsideInfo::shapeToRendererPoint(FloatPoint point) const +{ + FloatPoint result = FloatPoint(point.x() + logicalLeftOffset(), point.y() + logicalTopOffset()); + if (m_renderer.style()->isFlippedBlocksWritingMode()) + result.setY(m_renderer.logicalHeight() - result.y()); + if (!m_renderer.style()->isHorizontalWritingMode()) + result = result.transposedPoint(); + return result; +} + +FloatSize ShapeOutsideInfo::shapeToRendererSize(FloatSize size) const { - return m_renderer->style()->shapeOutside(); + if (!m_renderer.style()->isHorizontalWritingMode()) + return size.transposedSize(); + return size; } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.h index 82b31f65f69..36276e91fdb 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.h +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.h @@ -30,8 +30,13 @@ #ifndef ShapeOutsideInfo_h #define ShapeOutsideInfo_h -#include "core/rendering/shapes/ShapeInfo.h" +#include "core/rendering/shapes/Shape.h" +#include "core/rendering/style/RenderStyle.h" +#include "core/rendering/style/ShapeValue.h" +#include "platform/geometry/FloatRect.h" #include "platform/geometry/LayoutSize.h" +#include "wtf/OwnPtr.h" +#include "wtf/Vector.h" namespace WebCore { @@ -39,35 +44,85 @@ class RenderBlockFlow; class RenderBox; class FloatingObject; -class ShapeOutsideInfo FINAL : public ShapeInfo<RenderBox>, public MappedInfo<RenderBox, ShapeOutsideInfo> { +class ShapeOutsideInfo FINAL { + WTF_MAKE_FAST_ALLOCATED; public: + void setReferenceBoxLogicalSize(LayoutSize); + + SegmentList computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight) const; + + LayoutUnit shapeLogicalTop() const { return computedShape().shapeMarginLogicalBoundingBox().y() + logicalTopOffset(); } + LayoutUnit shapeLogicalBottom() const { return computedShape().shapeMarginLogicalBoundingBox().maxY() + logicalTopOffset(); } + LayoutUnit shapeLogicalLeft() const { return computedShape().shapeMarginLogicalBoundingBox().x() + logicalLeftOffset(); } + LayoutUnit shapeLogicalRight() const { return computedShape().shapeMarginLogicalBoundingBox().maxX() + logicalLeftOffset(); } + LayoutUnit shapeLogicalWidth() const { return computedShape().shapeMarginLogicalBoundingBox().width(); } + LayoutUnit shapeLogicalHeight() const { return computedShape().shapeMarginLogicalBoundingBox().height(); } + + LayoutUnit logicalLineTop() const { return m_referenceBoxLineTop + logicalTopOffset(); } + LayoutUnit logicalLineBottom() const { return m_referenceBoxLineTop + m_lineHeight + logicalTopOffset(); } + LayoutUnit leftMarginBoxDelta() const { return m_leftMarginBoxDelta; } LayoutUnit rightMarginBoxDelta() const { return m_rightMarginBoxDelta; } + bool lineOverlapsShape() const { return m_lineOverlapsShape; } - void updateDeltasForContainingBlockLine(const RenderBlockFlow*, const FloatingObject*, LayoutUnit lineTop, LayoutUnit lineHeight); + static PassOwnPtr<ShapeOutsideInfo> createInfo(const RenderBox& renderer) { return adoptPtr(new ShapeOutsideInfo(renderer)); } + static bool isEnabledFor(const RenderBox&); + void updateDeltasForContainingBlockLine(const RenderBlockFlow&, const FloatingObject&, LayoutUnit lineTop, LayoutUnit lineHeight); - static PassOwnPtr<ShapeOutsideInfo> createInfo(const RenderBox* renderer) { return adoptPtr(new ShapeOutsideInfo(renderer)); } - static bool isEnabledFor(const RenderBox*); + bool lineOverlapsShapeBounds() const + { + return computedShape().lineOverlapsShapeMarginBounds(m_referenceBoxLineTop, m_lineHeight); + } - virtual bool lineOverlapsShapeBounds() const OVERRIDE + static ShapeOutsideInfo& ensureInfo(const RenderBox& key) { - return computedShape()->lineOverlapsShapeMarginBounds(m_shapeLineTop, m_lineHeight); + InfoMap& infoMap = ShapeOutsideInfo::infoMap(); + if (ShapeOutsideInfo* info = infoMap.get(&key)) + return *info; + InfoMap::AddResult result = infoMap.add(&key, ShapeOutsideInfo::createInfo(key)); + return *result.storedValue->value; } + static void removeInfo(const RenderBox& key) { infoMap().remove(&key); } + static ShapeOutsideInfo* info(const RenderBox& key) { return infoMap().get(&key); } + + void markShapeAsDirty() { m_shape.clear(); } + bool isShapeDirty() { return !m_shape.get(); } + LayoutSize shapeSize() const { return m_referenceBoxLogicalSize; } + + LayoutRect computedShapePhysicalBoundingBox() const; + FloatPoint shapeToRendererPoint(FloatPoint) const; + FloatSize shapeToRendererSize(FloatSize) const; + const Shape& computedShape() const; protected: - virtual LayoutRect computedShapeLogicalBoundingBox() const OVERRIDE { return computedShape()->shapeMarginLogicalBoundingBox(); } - virtual ShapeValue* shapeValue() const OVERRIDE; - virtual void getIntervals(LayoutUnit lineTop, LayoutUnit lineHeight, SegmentList& segments) const OVERRIDE + ShapeOutsideInfo(const RenderBox& renderer) + : m_renderer(renderer) + , m_lineOverlapsShape(false) + { } + +private: + PassOwnPtr<Shape> createShapeForImage(StyleImage*, float shapeImageThreshold, WritingMode, float margin) const; + + LayoutUnit logicalTopOffset() const; + LayoutUnit logicalLeftOffset() const; + + typedef HashMap<const RenderBox*, OwnPtr<ShapeOutsideInfo> > InfoMap; + static InfoMap& infoMap() { - return computedShape()->getExcludedIntervals(lineTop, lineHeight, segments); + DEFINE_STATIC_LOCAL(InfoMap, staticInfoMap, ()); + return staticInfoMap; } -private: - ShapeOutsideInfo(const RenderBox* renderer) : ShapeInfo<RenderBox>(renderer) { } + LayoutUnit m_referenceBoxLineTop; + LayoutUnit m_lineHeight; + const RenderBox& m_renderer; + mutable OwnPtr<Shape> m_shape; + LayoutSize m_referenceBoxLogicalSize; LayoutUnit m_leftMarginBoxDelta; LayoutUnit m_rightMarginBoxDelta; - LayoutUnit m_lineTop; + LayoutUnit m_borderBoxLineTop; + bool m_lineOverlapsShape; }; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/AppliedTextDecoration.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/AppliedTextDecoration.cpp new file mode 100644 index 00000000000..ea8be8483a8 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/style/AppliedTextDecoration.cpp @@ -0,0 +1,36 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" +#include "core/rendering/style/AppliedTextDecoration.h" + +namespace WebCore { + +AppliedTextDecoration::AppliedTextDecoration(TextDecoration line, TextDecorationStyle style, StyleColor color) + : m_line(line) + , m_style(style) + , m_color(color) +{ +} + +AppliedTextDecoration::AppliedTextDecoration(TextDecoration line) + : m_line(line) + , m_style(TextDecorationStyleSolid) + , m_color(StyleColor::currentColor()) +{ +} + +AppliedTextDecoration::AppliedTextDecoration() + : m_line(TextDecorationUnderline) + , m_style(TextDecorationStyleSolid) + , m_color(StyleColor::currentColor()) +{ +} + +bool AppliedTextDecoration::operator==(const AppliedTextDecoration& o) const +{ + return m_color == o.m_color && m_line == o.m_line && m_style == o.m_style; +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/AppliedTextDecoration.h b/chromium/third_party/WebKit/Source/core/rendering/style/AppliedTextDecoration.h new file mode 100644 index 00000000000..fd0df809194 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/style/AppliedTextDecoration.h @@ -0,0 +1,34 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef AppliedTextDecoration_h +#define AppliedTextDecoration_h + +#include "core/css/StyleColor.h" +#include "core/rendering/style/RenderStyleConstants.h" + +namespace WebCore { + +class AppliedTextDecoration { +public: + AppliedTextDecoration(TextDecoration, TextDecorationStyle, StyleColor); + explicit AppliedTextDecoration(TextDecoration); + AppliedTextDecoration(); + + TextDecoration line() const { return static_cast<TextDecoration>(m_line); } + TextDecorationStyle style() const { return static_cast<TextDecorationStyle>(m_style); } + + bool isSimpleUnderline() const { return m_line == TextDecorationUnderline && m_style == TextDecorationStyleSolid && m_color.isCurrentColor(); } + bool operator==(const AppliedTextDecoration&) const; + bool operator!=(const AppliedTextDecoration& o) const { return !(*this == o); } + +private: + unsigned m_line : TextDecorationBits; + unsigned m_style : 3; // TextDecorationStyle + StyleColor m_color; +}; + +} // namespace WebCore + +#endif // AppliedTextDecoration_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/BasicShapes.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/BasicShapes.cpp index 1eed605f291..a41a1d6393c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/BasicShapes.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/BasicShapes.cpp @@ -28,70 +28,90 @@ */ #include "config.h" - #include "core/rendering/style/BasicShapes.h" + +#include "core/css/BasicShapeFunctions.h" +#include "platform/CalculationValue.h" #include "platform/LengthFunctions.h" #include "platform/geometry/FloatRect.h" #include "platform/graphics/Path.h" namespace WebCore { +void BasicShapeCenterCoordinate::updateComputedLength() +{ + if (m_direction == TopLeft) { + m_computedLength = m_length.isUndefined() ? Length(0, Fixed) : m_length; + return; + } + if (m_length.isUndefined()) { + m_computedLength = Length(100, Percent); + return; + } + + m_computedLength = m_length.subtractFromOneHundredPercent(); +} + bool BasicShape::canBlend(const BasicShape* other) const { // FIXME: Support animations between different shapes in the future. - if (type() != other->type()) + if (!other || !isSameType(*other)) return false; // Just polygons with same number of vertices can be animated. if (type() == BasicShape::BasicShapePolygonType - && static_cast<const BasicShapePolygon*>(this)->values().size() != static_cast<const BasicShapePolygon*>(other)->values().size()) + && (static_cast<const BasicShapePolygon*>(this)->values().size() != static_cast<const BasicShapePolygon*>(other)->values().size() + || static_cast<const BasicShapePolygon*>(this)->windRule() != static_cast<const BasicShapePolygon*>(other)->windRule())) return false; - return true; + // Circles with keywords for radii or center coordinates cannot be animated. + if (type() == BasicShape::BasicShapeCircleType) { + const BasicShapeCircle* thisCircle = static_cast<const BasicShapeCircle*>(this); + const BasicShapeCircle* otherCircle = static_cast<const BasicShapeCircle*>(other); + if (!thisCircle->radius().canBlend(otherCircle->radius())) + return false; + } + + // Ellipses with keywords for radii or center coordinates cannot be animated. + if (type() != BasicShape::BasicShapeEllipseType) + return true; + + const BasicShapeEllipse* thisEllipse = static_cast<const BasicShapeEllipse*>(this); + const BasicShapeEllipse* otherEllipse = static_cast<const BasicShapeEllipse*>(other); + return (thisEllipse->radiusX().canBlend(otherEllipse->radiusX()) + && thisEllipse->radiusY().canBlend(otherEllipse->radiusY())); } -void BasicShapeRectangle::path(Path& path, const FloatRect& boundingBox) +bool BasicShapeCircle::operator==(const BasicShape& o) const { - ASSERT(path.isEmpty()); - path.addRoundedRect( - FloatRect( - floatValueForLength(m_x, boundingBox.width()) + boundingBox.x(), - floatValueForLength(m_y, boundingBox.height()) + boundingBox.y(), - floatValueForLength(m_width, boundingBox.width()), - floatValueForLength(m_height, boundingBox.height()) - ), - FloatSize( - floatValueForLength(m_cornerRadiusX, boundingBox.width()), - floatValueForLength(m_cornerRadiusY, boundingBox.height()) - ) - ); + if (!isSameType(o)) + return false; + const BasicShapeCircle& other = toBasicShapeCircle(o); + return m_centerX == other.m_centerX && m_centerY == other.m_centerY && m_radius == other.m_radius; } -PassRefPtr<BasicShape> BasicShapeRectangle::blend(const BasicShape* other, double progress) const +float BasicShapeCircle::floatValueForRadiusInBox(FloatSize boxSize) const { - ASSERT(type() == other->type()); + if (m_radius.type() == BasicShapeRadius::Value) + return floatValueForLength(m_radius.value(), hypotf(boxSize.width(), boxSize.height()) / sqrtf(2)); - const BasicShapeRectangle* o = static_cast<const BasicShapeRectangle*>(other); - RefPtr<BasicShapeRectangle> result = BasicShapeRectangle::create(); - result->setX(m_x.blend(o->x(), progress, ValueRangeAll)); - result->setY(m_y.blend(o->y(), progress, ValueRangeAll)); - result->setWidth(m_width.blend(o->width(), progress, ValueRangeNonNegative)); - result->setHeight(m_height.blend(o->height(), progress, ValueRangeNonNegative)); - result->setCornerRadiusX(m_cornerRadiusX.blend(o->cornerRadiusX(), progress, ValueRangeNonNegative)); - result->setCornerRadiusY(m_cornerRadiusY.blend(o->cornerRadiusY(), progress, ValueRangeNonNegative)); - return result.release(); + FloatPoint center = floatPointForCenterCoordinate(m_centerX, m_centerY, boxSize); + + if (m_radius.type() == BasicShapeRadius::ClosestSide) + return std::min(std::min(center.x(), boxSize.width() - center.x()), std::min(center.y(), boxSize.height() - center.y())); + + // If radius.type() == BasicShapeRadius::FarthestSide. + return std::max(std::max(center.x(), boxSize.width() - center.x()), std::max(center.y(), boxSize.height() - center.y())); } void BasicShapeCircle::path(Path& path, const FloatRect& boundingBox) { ASSERT(path.isEmpty()); - float diagonal = sqrtf((boundingBox.width() * boundingBox.width() + boundingBox.height() * boundingBox.height()) / 2); - float centerX = floatValueForLength(m_centerX, boundingBox.width()); - float centerY = floatValueForLength(m_centerY, boundingBox.height()); - float radius = floatValueForLength(m_radius, diagonal); + FloatPoint center = floatPointForCenterCoordinate(m_centerX, m_centerY, boundingBox.size()); + float radius = floatValueForRadiusInBox(boundingBox.size()); path.addEllipse(FloatRect( - centerX - radius + boundingBox.x(), - centerY - radius + boundingBox.y(), + center.x() - radius + boundingBox.x(), + center.y() - radius + boundingBox.y(), radius * 2, radius * 2 )); @@ -100,25 +120,44 @@ void BasicShapeCircle::path(Path& path, const FloatRect& boundingBox) PassRefPtr<BasicShape> BasicShapeCircle::blend(const BasicShape* other, double progress) const { ASSERT(type() == other->type()); - const BasicShapeCircle* o = static_cast<const BasicShapeCircle*>(other); RefPtr<BasicShapeCircle> result = BasicShapeCircle::create(); - result->setCenterX(m_centerX.blend(o->centerX(), progress, ValueRangeAll)); - result->setCenterY(m_centerY.blend(o->centerY(), progress, ValueRangeAll)); - result->setRadius(m_radius.blend(o->radius(), progress, ValueRangeNonNegative)); + + result->setCenterX(m_centerX.blend(o->centerX(), progress)); + result->setCenterY(m_centerY.blend(o->centerY(), progress)); + result->setRadius(m_radius.blend(o->radius(), progress)); return result.release(); } +bool BasicShapeEllipse::operator==(const BasicShape& o) const +{ + if (!isSameType(o)) + return false; + const BasicShapeEllipse& other = toBasicShapeEllipse(o); + return m_centerX == other.m_centerX && m_centerY == other.m_centerY && m_radiusX == other.m_radiusX && m_radiusY == other.m_radiusY; +} + +float BasicShapeEllipse::floatValueForRadiusInBox(const BasicShapeRadius& radius, float center, float boxWidthOrHeight) const +{ + if (radius.type() == BasicShapeRadius::Value) + return floatValueForLength(radius.value(), boxWidthOrHeight); + + if (radius.type() == BasicShapeRadius::ClosestSide) + return std::min(center, boxWidthOrHeight - center); + + ASSERT(radius.type() == BasicShapeRadius::FarthestSide); + return std::max(center, boxWidthOrHeight - center); +} + void BasicShapeEllipse::path(Path& path, const FloatRect& boundingBox) { ASSERT(path.isEmpty()); - float centerX = floatValueForLength(m_centerX, boundingBox.width()); - float centerY = floatValueForLength(m_centerY, boundingBox.height()); - float radiusX = floatValueForLength(m_radiusX, boundingBox.width()); - float radiusY = floatValueForLength(m_radiusY, boundingBox.height()); + FloatPoint center = floatPointForCenterCoordinate(m_centerX, m_centerY, boundingBox.size()); + float radiusX = floatValueForRadiusInBox(m_radiusX, center.x(), boundingBox.width()); + float radiusY = floatValueForRadiusInBox(m_radiusY, center.y(), boundingBox.height()); path.addEllipse(FloatRect( - centerX - radiusX + boundingBox.x(), - centerY - radiusY + boundingBox.y(), + center.x() - radiusX + boundingBox.x(), + center.y() - radiusY + boundingBox.y(), radiusX * 2, radiusY * 2 )); @@ -127,13 +166,22 @@ void BasicShapeEllipse::path(Path& path, const FloatRect& boundingBox) PassRefPtr<BasicShape> BasicShapeEllipse::blend(const BasicShape* other, double progress) const { ASSERT(type() == other->type()); - const BasicShapeEllipse* o = static_cast<const BasicShapeEllipse*>(other); RefPtr<BasicShapeEllipse> result = BasicShapeEllipse::create(); - result->setCenterX(m_centerX.blend(o->centerX(), progress, ValueRangeAll)); - result->setCenterY(m_centerY.blend(o->centerY(), progress, ValueRangeAll)); - result->setRadiusX(m_radiusX.blend(o->radiusX(), progress, ValueRangeNonNegative)); - result->setRadiusY(m_radiusY.blend(o->radiusY(), progress, ValueRangeNonNegative)); + + if (m_radiusX.type() != BasicShapeRadius::Value || o->radiusX().type() != BasicShapeRadius::Value + || m_radiusY.type() != BasicShapeRadius::Value || o->radiusY().type() != BasicShapeRadius::Value) { + result->setCenterX(o->centerX()); + result->setCenterY(o->centerY()); + result->setRadiusX(o->radiusX()); + result->setRadiusY(o->radiusY()); + return result; + } + + result->setCenterX(m_centerX.blend(o->centerX(), progress)); + result->setCenterY(m_centerY.blend(o->centerY(), progress)); + result->setRadiusX(m_radiusX.blend(o->radiusX(), progress)); + result->setRadiusY(m_radiusY.blend(o->radiusY(), progress)); return result.release(); } @@ -157,7 +205,7 @@ void BasicShapePolygon::path(Path& path, const FloatRect& boundingBox) PassRefPtr<BasicShape> BasicShapePolygon::blend(const BasicShape* other, double progress) const { - ASSERT(type() == other->type()); + ASSERT(other && isSameType(*other)); const BasicShapePolygon* o = static_cast<const BasicShapePolygon*>(other); ASSERT(m_values.size() == o->values().size()); @@ -178,7 +226,21 @@ PassRefPtr<BasicShape> BasicShapePolygon::blend(const BasicShape* other, double return result.release(); } -void BasicShapeInsetRectangle::path(Path& path, const FloatRect& boundingBox) +bool BasicShapePolygon::operator==(const BasicShape& o) const +{ + if (!isSameType(o)) + return false; + const BasicShapePolygon& other = toBasicShapePolygon(o); + return m_windRule == other.m_windRule && m_values == other.m_values; +} + +static FloatSize floatSizeForLengthSize(const LengthSize& lengthSize, const FloatRect& boundingBox) +{ + return FloatSize(floatValueForLength(lengthSize.width(), boundingBox.width()), + floatValueForLength(lengthSize.height(), boundingBox.height())); +} + +void BasicShapeInset::path(Path& path, const FloatRect& boundingBox) { ASSERT(path.isEmpty()); float left = floatValueForLength(m_left, boundingBox.width()); @@ -190,25 +252,33 @@ void BasicShapeInsetRectangle::path(Path& path, const FloatRect& boundingBox) std::max<float>(boundingBox.width() - left - floatValueForLength(m_right, boundingBox.width()), 0), std::max<float>(boundingBox.height() - top - floatValueForLength(m_bottom, boundingBox.height()), 0) ), - FloatSize( - floatValueForLength(m_cornerRadiusX, boundingBox.width()), - floatValueForLength(m_cornerRadiusY, boundingBox.height()) - ) + floatSizeForLengthSize(m_topLeftRadius, boundingBox), + floatSizeForLengthSize(m_topRightRadius, boundingBox), + floatSizeForLengthSize(m_bottomLeftRadius, boundingBox), + floatSizeForLengthSize(m_bottomRightRadius, boundingBox) ); } -PassRefPtr<BasicShape> BasicShapeInsetRectangle::blend(const BasicShape* other, double progress) const +PassRefPtr<BasicShape> BasicShapeInset::blend(const BasicShape* other, double) const { ASSERT(type() == other->type()); + // FIXME: Implement blend for BasicShapeInset. + return nullptr; +} - const BasicShapeInsetRectangle* o = static_cast<const BasicShapeInsetRectangle*>(other); - RefPtr<BasicShapeInsetRectangle> result = BasicShapeInsetRectangle::create(); - result->setTop(m_top.blend(o->top(), progress, ValueRangeNonNegative)); - result->setRight(m_right.blend(o->right(), progress, ValueRangeNonNegative)); - result->setBottom(m_bottom.blend(o->bottom(), progress, ValueRangeNonNegative)); - result->setLeft(m_left.blend(o->left(), progress, ValueRangeNonNegative)); - result->setCornerRadiusX(m_cornerRadiusX.blend(o->cornerRadiusX(), progress, ValueRangeNonNegative)); - result->setCornerRadiusY(m_cornerRadiusY.blend(o->cornerRadiusY(), progress, ValueRangeNonNegative)); - return result.release(); +bool BasicShapeInset::operator==(const BasicShape& o) const +{ + if (!isSameType(o)) + return false; + const BasicShapeInset& other = toBasicShapeInset(o); + return m_right == other.m_right + && m_top == other.m_top + && m_bottom == other.m_bottom + && m_left == other.m_left + && m_topLeftRadius == other.m_topLeftRadius + && m_topRightRadius == other.m_topRightRadius + && m_bottomRightRadius == other.m_bottomRightRadius + && m_bottomLeftRadius == other.m_bottomLeftRadius; } + } diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/BasicShapes.h b/chromium/third_party/WebKit/Source/core/rendering/style/BasicShapes.h index b8735a82095..6f414688e28 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/BasicShapes.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/BasicShapes.h @@ -30,7 +30,9 @@ #ifndef BasicShapes_h #define BasicShapes_h +#include "core/rendering/style/RenderStyleConstants.h" #include "platform/Length.h" +#include "platform/LengthSize.h" #include "platform/graphics/WindRule.h" #include "wtf/RefCounted.h" #include "wtf/RefPtr.h" @@ -39,6 +41,7 @@ namespace WebCore { class FloatRect; +class FloatSize; class Path; class BasicShape : public RefCounted<BasicShape> { @@ -46,117 +49,174 @@ public: virtual ~BasicShape() { } enum Type { - BasicShapeRectangleType = 1, - BasicShapeCircleType = 2, - BasicShapeEllipseType = 3, - BasicShapePolygonType = 4, - BasicShapeInsetRectangleType = 5 + BasicShapeEllipseType, + BasicShapePolygonType, + BasicShapeCircleType, + BasicShapeInsetType }; bool canBlend(const BasicShape*) const; + bool isSameType(const BasicShape& other) const { return type() == other.type(); } virtual void path(Path&, const FloatRect&) = 0; virtual WindRule windRule() const { return RULE_NONZERO; } virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const = 0; + virtual bool operator==(const BasicShape&) const = 0; virtual Type type() const = 0; + protected: - BasicShape() { } + BasicShape() + { + } + }; -class BasicShapeRectangle : public BasicShape { +#define DEFINE_BASICSHAPE_TYPE_CASTS(thisType) \ + DEFINE_TYPE_CASTS(thisType, BasicShape, value, value->type() == BasicShape::thisType##Type, value.type() == BasicShape::thisType##Type) + +class BasicShapeCenterCoordinate { public: - static PassRefPtr<BasicShapeRectangle> create() { return adoptRef(new BasicShapeRectangle); } - - Length x() const { return m_x; } - Length y() const { return m_y; } - Length width() const { return m_width; } - Length height() const { return m_height; } - Length cornerRadiusX() const { return m_cornerRadiusX; } - Length cornerRadiusY() const { return m_cornerRadiusY; } - - void setX(Length x) { m_x = x; } - void setY(Length y) { m_y = y; } - void setWidth(Length width) { m_width = width; } - void setHeight(Length height) { m_height = height; } - void setCornerRadiusX(Length radiusX) + enum Direction { + TopLeft, + BottomRight + }; + BasicShapeCenterCoordinate() + : m_direction(TopLeft) + , m_length(Undefined) { - ASSERT(!radiusX.isUndefined()); - m_cornerRadiusX = radiusX; + updateComputedLength(); } - void setCornerRadiusY(Length radiusY) + + BasicShapeCenterCoordinate(Direction direction, const Length& length) + : m_direction(direction) + , m_length(length) { - ASSERT(!radiusY.isUndefined()); - m_cornerRadiusY = radiusY; + updateComputedLength(); } - virtual void path(Path&, const FloatRect&) OVERRIDE; - virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE; + BasicShapeCenterCoordinate(const BasicShapeCenterCoordinate& other) + : m_direction(other.direction()) + , m_length(other.length()) + , m_computedLength(other.m_computedLength) + { + } + + bool operator==(const BasicShapeCenterCoordinate& other) const { return m_direction == other.m_direction && m_length == other.m_length && m_computedLength == other.m_computedLength; } + + Direction direction() const { return m_direction; } + const Length& length() const { return m_length; } + const Length& computedLength() const { return m_computedLength; } + + BasicShapeCenterCoordinate blend(const BasicShapeCenterCoordinate& other, double progress) const + { + return BasicShapeCenterCoordinate(TopLeft, m_computedLength.blend(other.m_computedLength, progress, ValueRangeAll)); + } - virtual Type type() const { return BasicShapeRectangleType; } private: - BasicShapeRectangle() { } - - Length m_y; - Length m_x; - Length m_width; - Length m_height; - Length m_cornerRadiusX; - Length m_cornerRadiusY; + Direction m_direction; + Length m_length; + Length m_computedLength; + + void updateComputedLength(); }; -class BasicShapeCircle : public BasicShape { +class BasicShapeRadius { +public: + enum Type { + Value, + ClosestSide, + FarthestSide + }; + BasicShapeRadius() : m_value(Undefined), m_type(ClosestSide) { } + explicit BasicShapeRadius(const Length& v) : m_value(v), m_type(Value) { } + explicit BasicShapeRadius(Type t) : m_value(Undefined), m_type(t) { } + BasicShapeRadius(const BasicShapeRadius& other) : m_value(other.value()), m_type(other.type()) { } + bool operator==(const BasicShapeRadius& other) const { return m_type == other.m_type && m_value == other.m_value; } + + const Length& value() const { return m_value; } + Type type() const { return m_type; } + + bool canBlend(const BasicShapeRadius& other) const + { + // FIXME determine how to interpolate between keywords. See issue 330248. + return m_type == Value && other.type() == Value; + } + + BasicShapeRadius blend(const BasicShapeRadius& other, double progress) const + { + if (m_type != Value || other.type() != Value) + return BasicShapeRadius(other); + + return BasicShapeRadius(m_value.blend(other.value(), progress, ValueRangeNonNegative)); + } + +private: + Length m_value; + Type m_type; + +}; + +class BasicShapeCircle FINAL : public BasicShape { public: static PassRefPtr<BasicShapeCircle> create() { return adoptRef(new BasicShapeCircle); } - Length centerX() const { return m_centerX; } - Length centerY() const { return m_centerY; } - Length radius() const { return m_radius; } + const BasicShapeCenterCoordinate& centerX() const { return m_centerX; } + const BasicShapeCenterCoordinate& centerY() const { return m_centerY; } + const BasicShapeRadius& radius() const { return m_radius; } - void setCenterX(Length centerX) { m_centerX = centerX; } - void setCenterY(Length centerY) { m_centerY = centerY; } - void setRadius(Length radius) { m_radius = radius; } + float floatValueForRadiusInBox(FloatSize) const; + void setCenterX(BasicShapeCenterCoordinate centerX) { m_centerX = centerX; } + void setCenterY(BasicShapeCenterCoordinate centerY) { m_centerY = centerY; } + void setRadius(BasicShapeRadius radius) { m_radius = radius; } virtual void path(Path&, const FloatRect&) OVERRIDE; virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE; + virtual bool operator==(const BasicShape&) const OVERRIDE; - virtual Type type() const { return BasicShapeCircleType; } + virtual Type type() const OVERRIDE { return BasicShapeCircleType; } private: BasicShapeCircle() { } - Length m_centerX; - Length m_centerY; - Length m_radius; + BasicShapeCenterCoordinate m_centerX; + BasicShapeCenterCoordinate m_centerY; + BasicShapeRadius m_radius; }; -class BasicShapeEllipse : public BasicShape { +DEFINE_BASICSHAPE_TYPE_CASTS(BasicShapeCircle); + +class BasicShapeEllipse FINAL : public BasicShape { public: static PassRefPtr<BasicShapeEllipse> create() { return adoptRef(new BasicShapeEllipse); } - Length centerX() const { return m_centerX; } - Length centerY() const { return m_centerY; } - Length radiusX() const { return m_radiusX; } - Length radiusY() const { return m_radiusY; } + const BasicShapeCenterCoordinate& centerX() const { return m_centerX; } + const BasicShapeCenterCoordinate& centerY() const { return m_centerY; } + const BasicShapeRadius& radiusX() const { return m_radiusX; } + const BasicShapeRadius& radiusY() const { return m_radiusY; } + float floatValueForRadiusInBox(const BasicShapeRadius&, float center, float boxWidthOrHeight) const; - void setCenterX(Length centerX) { m_centerX = centerX; } - void setCenterY(Length centerY) { m_centerY = centerY; } - void setRadiusX(Length radiusX) { m_radiusX = radiusX; } - void setRadiusY(Length radiusY) { m_radiusY = radiusY; } + void setCenterX(BasicShapeCenterCoordinate centerX) { m_centerX = centerX; } + void setCenterY(BasicShapeCenterCoordinate centerY) { m_centerY = centerY; } + void setRadiusX(BasicShapeRadius radiusX) { m_radiusX = radiusX; } + void setRadiusY(BasicShapeRadius radiusY) { m_radiusY = radiusY; } virtual void path(Path&, const FloatRect&) OVERRIDE; virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE; + virtual bool operator==(const BasicShape&) const OVERRIDE; - virtual Type type() const { return BasicShapeEllipseType; } + virtual Type type() const OVERRIDE { return BasicShapeEllipseType; } private: BasicShapeEllipse() { } - Length m_centerX; - Length m_centerY; - Length m_radiusX; - Length m_radiusY; + BasicShapeCenterCoordinate m_centerX; + BasicShapeCenterCoordinate m_centerY; + BasicShapeRadius m_radiusX; + BasicShapeRadius m_radiusY; }; -class BasicShapePolygon : public BasicShape { +DEFINE_BASICSHAPE_TYPE_CASTS(BasicShapeEllipse); + +class BasicShapePolygon FINAL : public BasicShape { public: static PassRefPtr<BasicShapePolygon> create() { return adoptRef(new BasicShapePolygon); } @@ -165,14 +225,15 @@ public: Length getYAt(unsigned i) const { return m_values.at(2 * i + 1); } void setWindRule(WindRule windRule) { m_windRule = windRule; } - void appendPoint(Length x, Length y) { m_values.append(x); m_values.append(y); } + void appendPoint(const Length& x, const Length& y) { m_values.append(x); m_values.append(y); } virtual void path(Path&, const FloatRect&) OVERRIDE; virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE; + virtual bool operator==(const BasicShape&) const OVERRIDE; - virtual WindRule windRule() const { return m_windRule; } + virtual WindRule windRule() const OVERRIDE { return m_windRule; } - virtual Type type() const { return BasicShapePolygonType; } + virtual Type type() const OVERRIDE { return BasicShapePolygonType; } private: BasicShapePolygon() : m_windRule(RULE_NONZERO) @@ -182,45 +243,52 @@ private: Vector<Length> m_values; }; -class BasicShapeInsetRectangle : public BasicShape { +DEFINE_BASICSHAPE_TYPE_CASTS(BasicShapePolygon); + +class BasicShapeInset : public BasicShape { public: - static PassRefPtr<BasicShapeInsetRectangle> create() { return adoptRef(new BasicShapeInsetRectangle); } - - Length top() const { return m_top; } - Length right() const { return m_right; } - Length bottom() const { return m_bottom; } - Length left() const { return m_left; } - Length cornerRadiusX() const { return m_cornerRadiusX; } - Length cornerRadiusY() const { return m_cornerRadiusY; } - - void setTop(Length top) { m_top = top; } - void setRight(Length right) { m_right = right; } - void setBottom(Length bottom) { m_bottom = bottom; } - void setLeft(Length left) { m_left = left; } - void setCornerRadiusX(Length radiusX) - { - ASSERT(!radiusX.isUndefined()); - m_cornerRadiusX = radiusX; - } - void setCornerRadiusY(Length radiusY) - { - ASSERT(!radiusY.isUndefined()); - m_cornerRadiusY = radiusY; - } + static PassRefPtr<BasicShapeInset> create() { return adoptRef(new BasicShapeInset); } + + const Length& top() const { return m_top; } + const Length& right() const { return m_right; } + const Length& bottom() const { return m_bottom; } + const Length& left() const { return m_left; } + + const LengthSize& topLeftRadius() const { return m_topLeftRadius; } + const LengthSize& topRightRadius() const { return m_topRightRadius; } + const LengthSize& bottomRightRadius() const { return m_bottomRightRadius; } + const LengthSize& bottomLeftRadius() const { return m_bottomLeftRadius; } + + void setTop(const Length& top) { m_top = top; } + void setRight(const Length& right) { m_right = right; } + void setBottom(const Length& bottom) { m_bottom = bottom; } + void setLeft(const Length& left) { m_left = left; } + + void setTopLeftRadius(const LengthSize& radius) { m_topLeftRadius = radius; } + void setTopRightRadius(const LengthSize& radius) { m_topRightRadius = radius; } + void setBottomRightRadius(const LengthSize& radius) { m_bottomRightRadius = radius; } + void setBottomLeftRadius(const LengthSize& radius) { m_bottomLeftRadius = radius; } virtual void path(Path&, const FloatRect&) OVERRIDE; virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE; + virtual bool operator==(const BasicShape&) const OVERRIDE; - virtual Type type() const { return BasicShapeInsetRectangleType; } + virtual Type type() const OVERRIDE { return BasicShapeInsetType; } private: - BasicShapeInsetRectangle() { } + BasicShapeInset() { } Length m_right; Length m_top; Length m_bottom; Length m_left; - Length m_cornerRadiusX; - Length m_cornerRadiusY; + + LengthSize m_topLeftRadius; + LengthSize m_topRightRadius; + LengthSize m_bottomRightRadius; + LengthSize m_bottomLeftRadius; }; + +DEFINE_BASICSHAPE_TYPE_CASTS(BasicShapeInset); + } #endif diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/BorderData.h b/chromium/third_party/WebKit/Source/core/rendering/style/BorderData.h index bf96bcf797c..4df4644ebfe 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/BorderData.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/BorderData.h @@ -94,6 +94,19 @@ public: && m_topLeft == o.m_topLeft && m_topRight == o.m_topRight && m_bottomLeft == o.m_bottomLeft && m_bottomRight == o.m_bottomRight; } + bool visuallyEqual(const BorderData& o) const + { + return m_left.visuallyEqual(o.m_left) + && m_right.visuallyEqual(o.m_right) + && m_top.visuallyEqual(o.m_top) + && m_bottom.visuallyEqual(o.m_bottom) + && m_image == o.m_image + && m_topLeft == o.m_topLeft + && m_topRight == o.m_topRight + && m_bottomLeft == o.m_bottomLeft + && m_bottomRight == o.m_bottomRight; + } + bool operator!=(const BorderData& o) const { return !(*this == o); diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/BorderValue.h b/chromium/third_party/WebKit/Source/core/rendering/style/BorderValue.h index dcd5096df0b..211f0be97f9 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/BorderValue.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/BorderValue.h @@ -25,6 +25,7 @@ #ifndef BorderValue_h #define BorderValue_h +#include "core/css/StyleColor.h" #include "core/rendering/style/RenderStyleConstants.h" #include "platform/graphics/Color.h" @@ -35,7 +36,7 @@ friend class RenderStyle; public: BorderValue() : m_color(0) - , m_colorIsValid(false) + , m_colorIsCurrentColor(true) , m_width(3) , m_style(BNONE) , m_isAuto(AUTO_OFF) @@ -49,7 +50,7 @@ public: bool isTransparent() const { - return m_colorIsValid && !alphaChannel(m_color); + return !m_colorIsCurrentColor && !m_color.alpha(); } bool isVisible(bool checkStyle = true) const @@ -59,7 +60,17 @@ public: bool operator==(const BorderValue& o) const { - return m_width == o.m_width && m_style == o.m_style && m_color == o.m_color && m_colorIsValid == o.m_colorIsValid; + return m_width == o.m_width && m_style == o.m_style && m_color == o.m_color && m_colorIsCurrentColor == o.m_colorIsCurrentColor; + } + + // The default width is 3px, but if the style is none we compute a value of 0 (in RenderStyle itself) + bool visuallyEqual(const BorderValue& o) const + { + if (m_style == BNONE && o.m_style == BNONE) + return true; + if (m_style == BHIDDEN && o.m_style == BHIDDEN) + return true; + return *this == o; } bool operator!=(const BorderValue& o) const @@ -67,20 +78,20 @@ public: return !(*this == o); } - void setColor(const Color& color) + void setColor(const StyleColor& color) { - m_color = color.rgb(); - m_colorIsValid = color.isValid(); + m_color = color.resolve(Color()); + m_colorIsCurrentColor = color.isCurrentColor(); } - Color color() const { return Color(m_color, m_colorIsValid); } + StyleColor color() const { return m_colorIsCurrentColor ? StyleColor::currentColor() : StyleColor(m_color); } unsigned width() const { return m_width; } EBorderStyle style() const { return static_cast<EBorderStyle>(m_style); } protected: - RGBA32 m_color; - unsigned m_colorIsValid : 1; + Color m_color; + unsigned m_colorIsCurrentColor : 1; unsigned m_width : 26; unsigned m_style : 4; // EBorderStyle diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/CachedUAStyle.h b/chromium/third_party/WebKit/Source/core/rendering/style/CachedUAStyle.h index f56d66f3395..10bed857f56 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/CachedUAStyle.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/CachedUAStyle.h @@ -32,32 +32,31 @@ namespace WebCore { // applyMatchedProperties for later use during adjustRenderStyle. class CachedUAStyle { public: - CachedUAStyle() - : hasAppearance(false) - , backgroundLayers(BackgroundFillLayer) - { } + static PassOwnPtr<CachedUAStyle> create(const RenderStyle* style) + { + return adoptPtr(new CachedUAStyle(style)); + } + + bool hasAppearance; + BorderData border; + FillLayer backgroundLayers; + StyleColor backgroundColor; +private: explicit CachedUAStyle(const RenderStyle* style) - : hasAppearance(style->hasAppearance()) + : hasAppearance(true) , backgroundLayers(BackgroundFillLayer) + , backgroundColor(StyleColor::currentColor()) { - // RenderTheme::adjustStyle is the only consumer of this data. - // It only cares about the styles if appearance is set, - // so we cheat and don't bother to copy them when !hasAppearance. - if (!hasAppearance) - return; + ASSERT(style->hasAppearance()); border = style->border(); backgroundLayers = *style->backgroundLayers(); backgroundColor = style->backgroundColor(); } - - bool hasAppearance; - BorderData border; - FillLayer backgroundLayers; - Color backgroundColor; }; + } // namespace WebCore #endif // CachedUAStyle_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/CollapsedBorderValue.h b/chromium/third_party/WebKit/Source/core/rendering/style/CollapsedBorderValue.h index ef16dba2322..ac7b0575557 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/CollapsedBorderValue.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/CollapsedBorderValue.h @@ -33,7 +33,7 @@ class CollapsedBorderValue { public: CollapsedBorderValue() : m_color(0) - , m_colorIsValid(false) + , m_colorIsCurrentColor(true) , m_width(0) , m_style(BNONE) , m_precedence(BOFF) @@ -41,9 +41,9 @@ public: { } - CollapsedBorderValue(const BorderValue& border, const Color& color, EBorderPrecedence precedence) - : m_color(color.rgb()) - , m_colorIsValid(color.isValid()) + CollapsedBorderValue(const BorderValue& border, const StyleColor& color, EBorderPrecedence precedence) + : m_color(color.resolve(Color())) + , m_colorIsCurrentColor(color.isCurrentColor()) , m_width(border.nonZero() ? border.width() : 0) , m_style(border.style()) , m_precedence(precedence) @@ -54,7 +54,7 @@ public: unsigned width() const { return m_style > BHIDDEN ? m_width : 0; } EBorderStyle style() const { return static_cast<EBorderStyle>(m_style); } bool exists() const { return m_precedence != BOFF; } - Color color() const { return Color(m_color, m_colorIsValid); } + StyleColor color() const { return m_colorIsCurrentColor ? StyleColor::currentColor() : StyleColor(m_color); } bool isTransparent() const { return m_transparent; } EBorderPrecedence precedence() const { return static_cast<EBorderPrecedence>(m_precedence); } @@ -64,8 +64,8 @@ public: } private: - RGBA32 m_color; - unsigned m_colorIsValid : 1; + Color m_color; + unsigned m_colorIsCurrentColor : 1; unsigned m_width : 23; unsigned m_style : 4; // EBorderStyle unsigned m_precedence : 3; // EBorderPrecedence diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/ContentData.h b/chromium/third_party/WebKit/Source/core/rendering/style/ContentData.h index 77dd5619e9c..a01f6cc018f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/ContentData.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/ContentData.h @@ -66,7 +66,7 @@ private: OwnPtr<ContentData> m_next; }; -class ImageContentData : public ContentData { +class ImageContentData FINAL : public ContentData { friend class ContentData; public: const StyleImage* image() const { return m_image.get(); } @@ -89,7 +89,7 @@ private: { } - virtual PassOwnPtr<ContentData> cloneInternal() const + virtual PassOwnPtr<ContentData> cloneInternal() const OVERRIDE { RefPtr<StyleImage> image = const_cast<StyleImage*>(this->image()); return create(image.release()); @@ -98,7 +98,7 @@ private: RefPtr<StyleImage> m_image; }; -class TextContentData : public ContentData { +class TextContentData FINAL : public ContentData { friend class ContentData; public: const String& text() const { return m_text; } @@ -120,12 +120,12 @@ private: { } - virtual PassOwnPtr<ContentData> cloneInternal() const { return create(text()); } + virtual PassOwnPtr<ContentData> cloneInternal() const OVERRIDE { return create(text()); } String m_text; }; -class CounterContentData : public ContentData { +class CounterContentData FINAL : public ContentData { friend class ContentData; public: const CounterContent* counter() const { return m_counter.get(); } @@ -140,7 +140,7 @@ private: { } - virtual PassOwnPtr<ContentData> cloneInternal() const + virtual PassOwnPtr<ContentData> cloneInternal() const OVERRIDE { OwnPtr<CounterContent> counterData = adoptPtr(new CounterContent(*counter())); return create(counterData.release()); @@ -156,7 +156,7 @@ private: OwnPtr<CounterContent> m_counter; }; -class QuoteContentData : public ContentData { +class QuoteContentData FINAL : public ContentData { friend class ContentData; public: QuoteType quote() const { return m_quote; } @@ -178,7 +178,7 @@ private: { } - virtual PassOwnPtr<ContentData> cloneInternal() const { return create(quote()); } + virtual PassOwnPtr<ContentData> cloneInternal() const OVERRIDE { return create(quote()); } QuoteType m_quote; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/CursorList.h b/chromium/third_party/WebKit/Source/core/rendering/style/CursorList.h deleted file mode 100644 index 90bd00c181d..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/style/CursorList.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * (C) 2000 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) - * - * 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 CursorList_h -#define CursorList_h - -#include "core/rendering/style/CursorData.h" -#include "wtf/RefCounted.h" -#include "wtf/Vector.h" - -namespace WebCore { - -class CursorList : public RefCounted<CursorList> { -public: - static PassRefPtr<CursorList> create() - { - return adoptRef(new CursorList); - } - - const CursorData& operator[](int i) const { return m_vector[i]; } - CursorData& operator[](int i) { return m_vector[i]; } - const CursorData& at(size_t i) const { return m_vector.at(i); } - CursorData& at(size_t i) { return m_vector.at(i); } - - bool operator==(const CursorList& o) const { return m_vector == o.m_vector; } - bool operator!=(const CursorList& o) const { return m_vector != o.m_vector; } - - size_t size() const { return m_vector.size(); } - void append(const CursorData& cursorData) { m_vector.append(cursorData); } - -private: - CursorList() - { - } - - Vector<CursorData> m_vector; -}; - -} // namespace WebCore - -#endif // CursorList_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/DataEquivalency.h b/chromium/third_party/WebKit/Source/core/rendering/style/DataEquivalency.h new file mode 100644 index 00000000000..87d92388bbe --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/style/DataEquivalency.h @@ -0,0 +1,49 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DataEquivalency_h +#define DataEquivalency_h + +#include "wtf/OwnPtr.h" +#include "wtf/RefPtr.h" + +namespace WebCore { + +template <typename T> +bool dataEquivalent(const T* a, const T* b) +{ + if (a == b) + return true; + if (!a || !b) + return false; + return *a == *b; +} + +template <typename T> +bool dataEquivalent(const RefPtr<T>& a, const RefPtr<T>& b) +{ + return dataEquivalent(a.get(), b.get()); +} + +template <typename T> +bool dataEquivalent(const Persistent<T>& a, const Persistent<T>& b) +{ + return dataEquivalent(a.get(), b.get()); +} + +template <typename T> +bool dataEquivalent(const Member<T>& a, const Member<T>& b) +{ + return dataEquivalent(a.get(), b.get()); +} + +template <typename T> +bool dataEquivalent(const OwnPtr<T>& a, const OwnPtr<T>& b) +{ + return dataEquivalent(a.get(), b.get()); +} + +} // namespace WebCore + +#endif // DataEquivalency_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/FillLayer.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/FillLayer.cpp index 5a621e0c1f2..907a80d5b52 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/FillLayer.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/FillLayer.cpp @@ -22,6 +22,8 @@ #include "config.h" #include "core/rendering/style/FillLayer.h" +#include "core/rendering/style/DataEquivalency.h" + namespace WebCore { struct SameSizeAsFillLayer { @@ -34,8 +36,8 @@ struct SameSizeAsFillLayer { LengthSize m_sizeLength; - unsigned m_bitfields: 32; - unsigned m_bitfields2: 1; + unsigned m_bitfields1; + unsigned m_bitfields2; }; COMPILE_ASSERT(sizeof(FillLayer) == sizeof(SameSizeAsFillLayer), FillLayer_should_stay_small); @@ -159,7 +161,7 @@ bool FillLayer::operator==(const FillLayer& o) const { // We do not check the "isSet" booleans for each property, since those are only used during initial construction // to propagate patterns into layers. All layer comparisons happen after values have all been filled in anyway. - return StyleImage::imagesEquivalent(m_image.get(), o.m_image.get()) && m_xPosition == o.m_xPosition && m_yPosition == o.m_yPosition + return dataEquivalent(m_image, o.m_image) && m_xPosition == o.m_xPosition && m_yPosition == o.m_yPosition && m_backgroundXOrigin == o.m_backgroundXOrigin && m_backgroundYOrigin == o.m_backgroundYOrigin && m_attachment == o.m_attachment && m_clip == o.m_clip && m_composite == o.m_composite && m_blendMode == o.m_blendMode && m_origin == o.m_origin && m_repeatX == o.m_repeatX diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/FillLayer.h b/chromium/third_party/WebKit/Source/core/rendering/style/FillLayer.h index 790f202db1b..f79abaf9588 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/FillLayer.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/FillLayer.h @@ -40,7 +40,7 @@ struct FillSize { { } - FillSize(EFillSizeType t, LengthSize l) + FillSize(EFillSizeType t, const LengthSize& l) : type(t) , size(l) { @@ -66,8 +66,8 @@ public: ~FillLayer(); StyleImage* image() const { return m_image.get(); } - Length xPosition() const { return m_xPosition; } - Length yPosition() const { return m_yPosition; } + const Length& xPosition() const { return m_xPosition; } + const Length& yPosition() const { return m_yPosition; } BackgroundEdgeOrigin backgroundXOrigin() const { return static_cast<BackgroundEdgeOrigin>(m_backgroundXOrigin); } BackgroundEdgeOrigin backgroundYOrigin() const { return static_cast<BackgroundEdgeOrigin>(m_backgroundYOrigin); } EFillAttachment attachment() const { return static_cast<EFillAttachment>(m_attachment); } @@ -77,7 +77,7 @@ public: EFillRepeat repeatY() const { return static_cast<EFillRepeat>(m_repeatY); } CompositeOperator composite() const { return static_cast<CompositeOperator>(m_composite); } blink::WebBlendMode blendMode() const { return static_cast<blink::WebBlendMode>(m_blendMode); } - LengthSize sizeLength() const { return m_sizeLength; } + const LengthSize& sizeLength() const { return m_sizeLength; } EFillSizeType sizeType() const { return static_cast<EFillSizeType>(m_sizeType); } FillSize size() const { return FillSize(static_cast<EFillSizeType>(m_sizeType), m_sizeLength); } EMaskSourceType maskSourceType() const { return static_cast<EMaskSourceType>(m_maskSourceType); } @@ -101,8 +101,8 @@ public: bool isMaskSourceTypeSet() const { return m_maskSourceTypeSet; } void setImage(PassRefPtr<StyleImage> i) { m_image = i; m_imageSet = true; } - void setXPosition(Length position) { m_xPosition = position; m_xPosSet = true; m_backgroundXOriginSet = false; m_backgroundXOrigin = LeftEdge; } - void setYPosition(Length position) { m_yPosition = position; m_yPosSet = true; m_backgroundYOriginSet = false; m_backgroundYOrigin = TopEdge; } + void setXPosition(const Length& position) { m_xPosition = position; m_xPosSet = true; m_backgroundXOriginSet = false; m_backgroundXOrigin = LeftEdge; } + void setYPosition(const Length& position) { m_yPosition = position; m_yPosSet = true; m_backgroundYOriginSet = false; m_backgroundYOrigin = TopEdge; } void setBackgroundXOrigin(BackgroundEdgeOrigin origin) { m_backgroundXOrigin = origin; m_backgroundXOriginSet = true; } void setBackgroundYOrigin(BackgroundEdgeOrigin origin) { m_backgroundYOrigin = origin; m_backgroundYOriginSet = true; } void setAttachment(EFillAttachment attachment) { m_attachment = attachment; m_attachmentSet = true; } @@ -113,7 +113,7 @@ public: void setComposite(CompositeOperator c) { m_composite = c; m_compositeSet = true; } void setBlendMode(blink::WebBlendMode b) { m_blendMode = b; m_blendModeSet = true; } void setSizeType(EFillSizeType b) { m_sizeType = b; } - void setSizeLength(LengthSize l) { m_sizeLength = l; } + void setSizeLength(const LengthSize& l) { m_sizeLength = l; } void setSize(FillSize f) { m_sizeType = f.type; m_sizeLength = f.size; } void setMaskSourceType(EMaskSourceType m) { m_maskSourceType = m; m_maskSourceTypeSet = true; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/GridCoordinate.h b/chromium/third_party/WebKit/Source/core/rendering/style/GridCoordinate.h index 937d3f08b9b..fa78aa22a79 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/GridCoordinate.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/GridCoordinate.h @@ -31,36 +31,36 @@ #ifndef GridCoordinate_h #define GridCoordinate_h -#include "core/rendering/style/GridPosition.h" +#include "core/rendering/style/GridResolvedPosition.h" #include "wtf/HashMap.h" #include "wtf/PassOwnPtr.h" #include "wtf/text/WTFString.h" namespace WebCore { -// A span in a single direction (either rows or columns). Note that |initialPositionIndex| -// and |finalPositionIndex| are grid areas' indexes, NOT grid lines'. Iterating over the -// span should include both |initialPositionIndex| and |finalPositionIndex| to be correct. +// A span in a single direction (either rows or columns). Note that |resolvedInitialPosition| +// and |resolvedFinalPosition| are grid areas' indexes, NOT grid lines'. Iterating over the +// span should include both |resolvedInitialPosition| and |resolvedFinalPosition| to be correct. struct GridSpan { - static PassOwnPtr<GridSpan> create(size_t initialPosition, size_t finalPosition) + static PassOwnPtr<GridSpan> create(const GridResolvedPosition& resolvedInitialPosition, const GridResolvedPosition& resolvedFinalPosition) { - return adoptPtr(new GridSpan(initialPosition, finalPosition)); + return adoptPtr(new GridSpan(resolvedInitialPosition, resolvedFinalPosition)); } - static PassOwnPtr<GridSpan> createWithSpanAgainstOpposite(size_t resolvedOppositePosition, const GridPosition& position, GridPositionSide side) + static PassOwnPtr<GridSpan> createWithSpanAgainstOpposite(const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side) { // 'span 1' is contained inside a single grid track regardless of the direction. // That's why the CSS span value is one more than the offset we apply. size_t positionOffset = position.spanPosition() - 1; if (side == ColumnStartSide || side == RowStartSide) { - size_t initialResolvedPosition = std::max<int>(0, resolvedOppositePosition - positionOffset); + GridResolvedPosition initialResolvedPosition = GridResolvedPosition(std::max<int>(0, resolvedOppositePosition.toInt() - positionOffset)); return GridSpan::create(initialResolvedPosition, resolvedOppositePosition); } - return GridSpan::create(resolvedOppositePosition, resolvedOppositePosition + positionOffset); + return GridSpan::create(resolvedOppositePosition, GridResolvedPosition(resolvedOppositePosition.toInt() + positionOffset)); } - static PassOwnPtr<GridSpan> createWithNamedSpanAgainstOpposite(size_t resolvedOppositePosition, const GridPosition& position, GridPositionSide side, const Vector<size_t>& gridLines) + static PassOwnPtr<GridSpan> createWithNamedSpanAgainstOpposite(const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side, const Vector<size_t>& gridLines) { if (side == RowStartSide || side == ColumnStartSide) return createWithInitialNamedSpanAgainstOpposite(resolvedOppositePosition, position, gridLines); @@ -68,50 +68,71 @@ struct GridSpan { return createWithFinalNamedSpanAgainstOpposite(resolvedOppositePosition, position, gridLines); } - static PassOwnPtr<GridSpan> createWithInitialNamedSpanAgainstOpposite(size_t resolvedOppositePosition, const GridPosition& position, const Vector<size_t>& gridLines) + static PassOwnPtr<GridSpan> createWithInitialNamedSpanAgainstOpposite(const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, const Vector<size_t>& gridLines) { // The grid line inequality needs to be strict (which doesn't match the after / end case) because |resolvedOppositePosition| // is already converted to an index in our grid representation (ie one was removed from the grid line to account for the side). size_t firstLineBeforeOppositePositionIndex = 0; - const size_t* firstLineBeforeOppositePosition = std::lower_bound(gridLines.begin(), gridLines.end(), resolvedOppositePosition); - if (firstLineBeforeOppositePosition != gridLines.end()) + const size_t* firstLineBeforeOppositePosition = std::lower_bound(gridLines.begin(), gridLines.end(), resolvedOppositePosition.toInt()); + if (firstLineBeforeOppositePosition != gridLines.end()) { + if (*firstLineBeforeOppositePosition > resolvedOppositePosition.toInt() && firstLineBeforeOppositePosition != gridLines.begin()) + --firstLineBeforeOppositePosition; + firstLineBeforeOppositePositionIndex = firstLineBeforeOppositePosition - gridLines.begin(); + } size_t gridLineIndex = std::max<int>(0, firstLineBeforeOppositePositionIndex - position.spanPosition() + 1); - size_t resolvedGridLinePosition = gridLines[gridLineIndex]; + GridResolvedPosition resolvedGridLinePosition = GridResolvedPosition(gridLines[gridLineIndex]); if (resolvedGridLinePosition > resolvedOppositePosition) resolvedGridLinePosition = resolvedOppositePosition; return GridSpan::create(resolvedGridLinePosition, resolvedOppositePosition); } - static PassOwnPtr<GridSpan> createWithFinalNamedSpanAgainstOpposite(size_t resolvedOppositePosition, const GridPosition& position, const Vector<size_t>& gridLines) + static PassOwnPtr<GridSpan> createWithFinalNamedSpanAgainstOpposite(const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, const Vector<size_t>& gridLines) { size_t firstLineAfterOppositePositionIndex = gridLines.size() - 1; - const size_t* firstLineAfterOppositePosition = std::upper_bound(gridLines.begin(), gridLines.end(), resolvedOppositePosition); + const size_t* firstLineAfterOppositePosition = std::upper_bound(gridLines.begin(), gridLines.end(), resolvedOppositePosition.toInt()); if (firstLineAfterOppositePosition != gridLines.end()) firstLineAfterOppositePositionIndex = firstLineAfterOppositePosition - gridLines.begin(); size_t gridLineIndex = std::min(gridLines.size() - 1, firstLineAfterOppositePositionIndex + position.spanPosition() - 1); - size_t resolvedGridLinePosition = GridPosition::adjustGridPositionForAfterEndSide(gridLines[gridLineIndex]); + GridResolvedPosition resolvedGridLinePosition = GridResolvedPosition::adjustGridPositionForAfterEndSide(gridLines[gridLineIndex]); if (resolvedGridLinePosition < resolvedOppositePosition) resolvedGridLinePosition = resolvedOppositePosition; return GridSpan::create(resolvedOppositePosition, resolvedGridLinePosition); } - GridSpan(size_t initialPosition, size_t finalPosition) - : initialPositionIndex(initialPosition) - , finalPositionIndex(finalPosition) + GridSpan(const GridResolvedPosition& resolvedInitialPosition, const GridResolvedPosition& resolvedFinalPosition) + : resolvedInitialPosition(resolvedInitialPosition) + , resolvedFinalPosition(resolvedFinalPosition) { - ASSERT(initialPositionIndex <= finalPositionIndex); + ASSERT(resolvedInitialPosition <= resolvedFinalPosition); } bool operator==(const GridSpan& o) const { - return initialPositionIndex == o.initialPositionIndex && finalPositionIndex == o.finalPositionIndex; + return resolvedInitialPosition == o.resolvedInitialPosition && resolvedFinalPosition == o.resolvedFinalPosition; + } + + size_t integerSpan() const + { + return resolvedFinalPosition.toInt() - resolvedInitialPosition.toInt() + 1; + } + + GridResolvedPosition resolvedInitialPosition; + GridResolvedPosition resolvedFinalPosition; + + typedef GridResolvedPosition iterator; + + iterator begin() const + { + return resolvedInitialPosition; } - size_t initialPositionIndex; - size_t finalPositionIndex; + iterator end() const + { + return resolvedFinalPosition.next(); + } }; // This represents a grid area that spans in both rows' and columns' direction. @@ -139,6 +160,22 @@ struct GridCoordinate { return !(*this == o); } + GridResolvedPosition positionForSide(GridPositionSide side) const + { + switch (side) { + case ColumnStartSide: + return columns.resolvedInitialPosition; + case ColumnEndSide: + return columns.resolvedFinalPosition; + case RowStartSide: + return rows.resolvedInitialPosition; + case RowEndSide: + return rows.resolvedFinalPosition; + } + ASSERT_NOT_REACHED(); + return 0; + } + GridSpan columns; GridSpan rows; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/GridLength.h b/chromium/third_party/WebKit/Source/core/rendering/style/GridLength.h index dadf7dac255..e822d08ab0b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/GridLength.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/GridLength.h @@ -40,17 +40,17 @@ namespace WebCore { // an new unit to Length.h. class GridLength { public: - GridLength() - : m_length(Undefined) + GridLength(const Length& length) + : m_length(length) , m_flex(0) , m_type(LengthType) { + ASSERT(!length.isUndefined()); } - GridLength(const Length& length) - : m_length(length) - , m_flex(0) - , m_type(LengthType) + explicit GridLength(double flex) + : m_flex(flex) + , m_type(FlexType) { } @@ -58,14 +58,8 @@ public: bool isFlex() const { return m_type == FlexType; } const Length& length() const { ASSERT(isLength()); return m_length; } - Length& length() { ASSERT(isLength()); return m_length; } double flex() const { ASSERT(isFlex()); return m_flex; } - void setFlex(double flex) - { - m_type = FlexType; - m_flex = flex; - } bool operator==(const GridLength& o) const { diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/GridPosition.h b/chromium/third_party/WebKit/Source/core/rendering/style/GridPosition.h index 133cdd55123..bb404909546 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/GridPosition.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/GridPosition.h @@ -42,13 +42,6 @@ enum GridPositionType { NamedGridAreaPosition // <ident> }; -enum GridPositionSide { - ColumnStartSide, - ColumnEndSide, - RowStartSide, - RowEndSide -}; - class GridPosition { public: GridPosition() @@ -57,20 +50,6 @@ public: { } - static size_t adjustGridPositionForAfterEndSide(size_t resolvedPosition) - { - return resolvedPosition ? resolvedPosition - 1 : 0; - } - - static size_t adjustGridPositionForSide(size_t resolvedPosition, GridPositionSide side) - { - // An item finishing on the N-th line belongs to the N-1-th cell. - if (side == ColumnEndSide || side == RowEndSide) - return adjustGridPositionForAfterEndSide(resolvedPosition); - - return resolvedPosition; - } - bool isPositive() const { return integerPosition() > 0; } GridPositionType type() const { return m_type; } @@ -85,6 +64,12 @@ public: m_namedGridLine = namedGridLine; } + void setAutoPosition() + { + m_type = AutoPosition; + m_integerPosition = 0; + } + // 'span' values cannot be negative, yet we reuse the <integer> position which can // be. This means that we have to convert the span position to an integer, losing // some precision here. It shouldn't be an issue in practice though. diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/GridResolvedPosition.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/GridResolvedPosition.cpp new file mode 100644 index 00000000000..b537048b75c --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/style/GridResolvedPosition.cpp @@ -0,0 +1,253 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" +#include "core/rendering/style/GridResolvedPosition.h" + +#include "core/rendering/RenderBox.h" +#include "core/rendering/style/GridCoordinate.h" + +namespace WebCore { + +static const NamedGridLinesMap& gridLinesForSide(const RenderStyle& style, GridPositionSide side) +{ + return (side == ColumnStartSide || side == ColumnEndSide) ? style.namedGridColumnLines() : style.namedGridRowLines(); +} + +static inline String implicitNamedGridLineForSide(const String& lineName, GridPositionSide side) +{ + return lineName + ((side == ColumnStartSide || side == RowStartSide) ? "-start" : "-end"); +} + +static bool isValidNamedLineOrArea(const String& lineName, const RenderStyle& style, GridPositionSide side) +{ + const NamedGridLinesMap& gridLineNames = gridLinesForSide(style, side); + + return gridLineNames.contains(implicitNamedGridLineForSide(lineName, side)) || gridLineNames.contains(lineName); +} + +static GridPositionSide calculateInitialPositionSide(GridTrackSizingDirection direction) +{ + return (direction == ForColumns) ? ColumnStartSide : RowStartSide; +} + +static GridPositionSide calculateFinalPositionSide(GridTrackSizingDirection direction) +{ + return (direction == ForColumns) ? ColumnEndSide : RowEndSide; +} + +void GridResolvedPosition::initialAndFinalPositionsFromStyle(const RenderStyle& gridContainerStyle, const RenderBox& gridItem, GridTrackSizingDirection direction, GridPosition& initialPosition, GridPosition& finalPosition) +{ + initialPosition = (direction == ForColumns) ? gridItem.style()->gridColumnStart() : gridItem.style()->gridRowStart(); + finalPosition = (direction == ForColumns) ? gridItem.style()->gridColumnEnd() : gridItem.style()->gridRowEnd(); + GridPositionSide initialPositionSide = calculateInitialPositionSide(direction); + GridPositionSide finalPositionSide = calculateFinalPositionSide(direction); + + // We must handle the placement error handling code here instead of in the StyleAdjuster because we don't want to + // overwrite the specified values. + if (initialPosition.isSpan() && finalPosition.isSpan()) + finalPosition.setAutoPosition(); + + // Try to early detect the case of non existing named grid lines. This way we could assume later that + // GridResolvedPosition::resolveGrisPositionFromStyle() always return a valid resolved position. + if (initialPosition.isNamedGridArea() && !isValidNamedLineOrArea(initialPosition.namedGridLine(), gridContainerStyle, initialPositionSide)) + initialPosition.setAutoPosition(); + + if (finalPosition.isNamedGridArea() && !isValidNamedLineOrArea(finalPosition.namedGridLine(), gridContainerStyle, finalPositionSide)) + finalPosition.setAutoPosition(); + + // If the grid item has an automatic position and a grid span for a named line in a given dimension, instead treat the grid span as one. + if (initialPosition.isAuto() && finalPosition.isSpan() && !finalPosition.namedGridLine().isNull()) + finalPosition.setSpanPosition(1, String()); + if (finalPosition.isAuto() && initialPosition.isSpan() && !initialPosition.namedGridLine().isNull()) + initialPosition.setSpanPosition(1, String()); +} + +GridSpan GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(const RenderStyle& gridContainerStyle, const RenderBox& gridItem, GridTrackSizingDirection direction, const GridResolvedPosition& resolvedInitialPosition) +{ + GridPosition initialPosition, finalPosition; + initialAndFinalPositionsFromStyle(gridContainerStyle, gridItem, direction, initialPosition, finalPosition); + + GridPositionSide finalPositionSide = calculateFinalPositionSide(direction); + + // This method will only be used when both positions need to be resolved against the opposite one. + ASSERT(initialPosition.shouldBeResolvedAgainstOppositePosition() && finalPosition.shouldBeResolvedAgainstOppositePosition()); + + GridResolvedPosition resolvedFinalPosition = resolvedInitialPosition; + + if (initialPosition.isSpan()) { + resolvedFinalPosition = resolveGridPositionAgainstOppositePosition(gridContainerStyle, resolvedInitialPosition, initialPosition, finalPositionSide)->resolvedFinalPosition; + } else if (finalPosition.isSpan()) { + resolvedFinalPosition = resolveGridPositionAgainstOppositePosition(gridContainerStyle, resolvedInitialPosition, finalPosition, finalPositionSide)->resolvedFinalPosition; + } + + return GridSpan(resolvedInitialPosition, resolvedFinalPosition); +} + +PassOwnPtr<GridSpan> GridResolvedPosition::resolveGridPositionsFromStyle(const RenderStyle& gridContainerStyle, const RenderBox& gridItem, GridTrackSizingDirection direction) +{ + GridPosition initialPosition, finalPosition; + initialAndFinalPositionsFromStyle(gridContainerStyle, gridItem, direction, initialPosition, finalPosition); + + GridPositionSide initialPositionSide = calculateInitialPositionSide(direction); + GridPositionSide finalPositionSide = calculateFinalPositionSide(direction); + + if (initialPosition.shouldBeResolvedAgainstOppositePosition() && finalPosition.shouldBeResolvedAgainstOppositePosition()) { + if (gridContainerStyle.gridAutoFlow() == AutoFlowNone) + return adoptPtr(new GridSpan(0, 0)); + + // We can't get our grid positions without running the auto placement algorithm. + return nullptr; + } + + if (initialPosition.shouldBeResolvedAgainstOppositePosition()) { + // Infer the position from the final position ('auto / 1' or 'span 2 / 3' case). + GridResolvedPosition finalResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalPositionSide); + return resolveGridPositionAgainstOppositePosition(gridContainerStyle, finalResolvedPosition, initialPosition, initialPositionSide); + } + + if (finalPosition.shouldBeResolvedAgainstOppositePosition()) { + // Infer our position from the initial position ('1 / auto' or '3 / span 2' case). + GridResolvedPosition initialResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialPositionSide); + return resolveGridPositionAgainstOppositePosition(gridContainerStyle, initialResolvedPosition, finalPosition, finalPositionSide); + } + + GridResolvedPosition resolvedInitialPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialPositionSide); + GridResolvedPosition resolvedFinalPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalPositionSide); + + // If 'grid-after' specifies a line at or before that specified by 'grid-before', it computes to 'span 1'. + if (resolvedFinalPosition < resolvedInitialPosition) + resolvedFinalPosition = resolvedInitialPosition; + + return adoptPtr(new GridSpan(resolvedInitialPosition, resolvedFinalPosition)); +} + +size_t GridResolvedPosition::explicitGridColumnCount(const RenderStyle& gridContainerStyle) +{ + return gridContainerStyle.gridTemplateColumns().size(); +} + +size_t GridResolvedPosition::explicitGridRowCount(const RenderStyle& gridContainerStyle) +{ + return gridContainerStyle.gridTemplateRows().size(); +} + +size_t GridResolvedPosition::explicitGridSizeForSide(const RenderStyle& gridContainerStyle, GridPositionSide side) +{ + return (side == ColumnStartSide || side == ColumnEndSide) ? explicitGridColumnCount(gridContainerStyle) : explicitGridRowCount(gridContainerStyle); +} + +GridResolvedPosition GridResolvedPosition::resolveNamedGridLinePositionFromStyle(const RenderStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side) +{ + ASSERT(!position.namedGridLine().isNull()); + + const NamedGridLinesMap& gridLinesNames = gridLinesForSide(gridContainerStyle, side); + NamedGridLinesMap::const_iterator it = gridLinesNames.find(position.namedGridLine()); + if (it == gridLinesNames.end()) { + if (position.isPositive()) + return GridResolvedPosition(0); + const size_t lastLine = explicitGridSizeForSide(gridContainerStyle, side); + return adjustGridPositionForSide(lastLine, side); + } + + size_t namedGridLineIndex; + if (position.isPositive()) + namedGridLineIndex = std::min<size_t>(position.integerPosition(), it->value.size()) - 1; + else + namedGridLineIndex = std::max<int>(it->value.size() - abs(position.integerPosition()), 0); + return adjustGridPositionForSide(it->value[namedGridLineIndex], side); +} + +GridResolvedPosition GridResolvedPosition::resolveGridPositionFromStyle(const RenderStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side) +{ + switch (position.type()) { + case ExplicitPosition: { + ASSERT(position.integerPosition()); + + if (!position.namedGridLine().isNull()) + return resolveNamedGridLinePositionFromStyle(gridContainerStyle, position, side); + + // Handle <integer> explicit position. + if (position.isPositive()) + return adjustGridPositionForSide(position.integerPosition() - 1, side); + + size_t resolvedPosition = abs(position.integerPosition()) - 1; + const size_t endOfTrack = explicitGridSizeForSide(gridContainerStyle, side); + + // Per http://lists.w3.org/Archives/Public/www-style/2013Mar/0589.html, we clamp negative value to the first line. + if (endOfTrack < resolvedPosition) + return GridResolvedPosition(0); + + return adjustGridPositionForSide(endOfTrack - resolvedPosition, side); + } + case NamedGridAreaPosition: + { + // First attempt to match the grid area’s edge to a named grid area: if there is a named line with the name + // ''<custom-ident>-start (for grid-*-start) / <custom-ident>-end'' (for grid-*-end), contributes the first such + // line to the grid item’s placement. + String namedGridLine = position.namedGridLine(); + ASSERT(isValidNamedLineOrArea(namedGridLine, gridContainerStyle, side)); + + const NamedGridLinesMap& gridLineNames = gridLinesForSide(gridContainerStyle, side); + NamedGridLinesMap::const_iterator implicitLineIter = gridLineNames.find(implicitNamedGridLineForSide(namedGridLine, side)); + if (implicitLineIter != gridLineNames.end()) + return adjustGridPositionForSide(implicitLineIter->value[0], side); + + // Otherwise, if there is a named line with the specified name, contributes the first such line to the grid + // item’s placement. + NamedGridLinesMap::const_iterator explicitLineIter = gridLineNames.find(namedGridLine); + if (explicitLineIter != gridLineNames.end()) + return adjustGridPositionForSide(explicitLineIter->value[0], side); + + // If none of the above works specs mandate us to treat it as auto BUT we should have detected it before calling + // this function in GridResolvedPosition::resolveGridPositionsFromStyle(). We should be also covered by the + // ASSERT at the beginning of this block. + ASSERT_NOT_REACHED(); + return GridResolvedPosition(0); + } + case AutoPosition: + case SpanPosition: + // 'auto' and span depend on the opposite position for resolution (e.g. grid-row: auto / 1 or grid-column: span 3 / "myHeader"). + ASSERT_NOT_REACHED(); + return GridResolvedPosition(0); + } + ASSERT_NOT_REACHED(); + return GridResolvedPosition(0); +} + +PassOwnPtr<GridSpan> GridResolvedPosition::resolveGridPositionAgainstOppositePosition(const RenderStyle& gridContainerStyle, const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side) +{ + if (position.isAuto()) + return GridSpan::create(resolvedOppositePosition, resolvedOppositePosition); + + ASSERT(position.isSpan()); + ASSERT(position.spanPosition() > 0); + + if (!position.namedGridLine().isNull()) { + // span 2 'c' -> we need to find the appropriate grid line before / after our opposite position. + return resolveNamedGridLinePositionAgainstOppositePosition(gridContainerStyle, resolvedOppositePosition, position, side); + } + + return GridSpan::createWithSpanAgainstOpposite(resolvedOppositePosition, position, side); +} + +PassOwnPtr<GridSpan> GridResolvedPosition::resolveNamedGridLinePositionAgainstOppositePosition(const RenderStyle& gridContainerStyle, const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side) +{ + ASSERT(position.isSpan()); + ASSERT(!position.namedGridLine().isNull()); + // Negative positions are not allowed per the specification and should have been handled during parsing. + ASSERT(position.spanPosition() > 0); + + const NamedGridLinesMap& gridLinesNames = gridLinesForSide(gridContainerStyle, side); + NamedGridLinesMap::const_iterator it = gridLinesNames.find(position.namedGridLine()); + + // If there is no named grid line of that name, we resolve the position to 'auto' (which is equivalent to 'span 1' in this case). + // See http://lists.w3.org/Archives/Public/www-style/2013Jun/0394.html. + if (it == gridLinesNames.end()) + return GridSpan::create(resolvedOppositePosition, resolvedOppositePosition); + + return GridSpan::createWithNamedSpanAgainstOpposite(resolvedOppositePosition, position, side, it->value); +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/GridResolvedPosition.h b/chromium/third_party/WebKit/Source/core/rendering/style/GridResolvedPosition.h new file mode 100644 index 00000000000..e9a79566736 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/style/GridResolvedPosition.h @@ -0,0 +1,125 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GridResolvedPosition_h +#define GridResolvedPosition_h + +#include "core/rendering/style/GridPosition.h" + +namespace WebCore { + +struct GridSpan; +class RenderBox; +class RenderStyle; + +enum GridPositionSide { + ColumnStartSide, + ColumnEndSide, + RowStartSide, + RowEndSide +}; + +enum GridTrackSizingDirection { + ForColumns, + ForRows +}; + +// This class represents an index into one of the dimensions of the grid array. +// Wraps a size_t integer just for the purpose of knowing what we manipulate in the grid code. +class GridResolvedPosition { +public: + static GridResolvedPosition adjustGridPositionForAfterEndSide(size_t resolvedPosition) + { + return resolvedPosition ? GridResolvedPosition(resolvedPosition - 1) : GridResolvedPosition(0); + } + + static GridResolvedPosition adjustGridPositionForSide(size_t resolvedPosition, GridPositionSide side) + { + // An item finishing on the N-th line belongs to the N-1-th cell. + if (side == ColumnEndSide || side == RowEndSide) + return adjustGridPositionForAfterEndSide(resolvedPosition); + + return GridResolvedPosition(resolvedPosition); + } + + static void initialAndFinalPositionsFromStyle(const RenderStyle&, const RenderBox&, GridTrackSizingDirection, GridPosition &initialPosition, GridPosition &finalPosition); + static GridSpan resolveGridPositionsFromAutoPlacementPosition(const RenderStyle&, const RenderBox&, GridTrackSizingDirection, const GridResolvedPosition&); + static PassOwnPtr<GridSpan> resolveGridPositionsFromStyle(const RenderStyle&, const RenderBox&, GridTrackSizingDirection); + static GridResolvedPosition resolveNamedGridLinePositionFromStyle(const RenderStyle&, const GridPosition&, GridPositionSide); + static GridResolvedPosition resolveGridPositionFromStyle(const RenderStyle&, const GridPosition&, GridPositionSide); + static PassOwnPtr<GridSpan> resolveGridPositionAgainstOppositePosition(const RenderStyle&, const GridResolvedPosition& resolvedOppositePosition, const GridPosition&, GridPositionSide); + static PassOwnPtr<GridSpan> resolveNamedGridLinePositionAgainstOppositePosition(const RenderStyle&, const GridResolvedPosition& resolvedOppositePosition, const GridPosition&, GridPositionSide); + + GridResolvedPosition(size_t position) + : m_integerPosition(position) + { + } + + GridResolvedPosition(const GridPosition& position, GridPositionSide side) + { + ASSERT(position.integerPosition()); + size_t integerPosition = position.integerPosition() - 1; + + m_integerPosition = adjustGridPositionForSide(integerPosition, side).toInt(); + } + + GridResolvedPosition& operator++() + { + m_integerPosition++; + return *this; + } + + bool operator==(const GridResolvedPosition& other) const + { + return m_integerPosition == other.m_integerPosition; + } + + bool operator!=(const GridResolvedPosition& other) const + { + return m_integerPosition != other.m_integerPosition; + } + + bool operator<(const GridResolvedPosition& other) const + { + return m_integerPosition < other.m_integerPosition; + } + + bool operator>(const GridResolvedPosition& other) const + { + return m_integerPosition > other.m_integerPosition; + } + + bool operator<=(const GridResolvedPosition& other) const + { + return m_integerPosition <= other.m_integerPosition; + } + + bool operator>=(const GridResolvedPosition& other) const + { + return m_integerPosition >= other.m_integerPosition; + } + + size_t toInt() const + { + return m_integerPosition; + } + + GridResolvedPosition next() const + { + return GridResolvedPosition(m_integerPosition + 1); + } + + static size_t explicitGridColumnCount(const RenderStyle&); + static size_t explicitGridRowCount(const RenderStyle&); + +private: + + static size_t explicitGridSizeForSide(const RenderStyle&, GridPositionSide); + + size_t m_integerPosition; +}; + +} // namespace WebCore + +#endif // GridResolvedPosition_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/GridTrackSize.h b/chromium/third_party/WebKit/Source/core/rendering/style/GridTrackSize.h index 584b47a4024..b64e5e3bc21 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/GridTrackSize.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/GridTrackSize.h @@ -42,30 +42,27 @@ enum GridTrackSizeType { class GridTrackSize { public: - GridTrackSize() + GridTrackSize(const GridLength& length) : m_type(LengthTrackSizing) - , m_minTrackBreadth(Undefined) - , m_maxTrackBreadth(Undefined) + , m_minTrackBreadth(length) + , m_maxTrackBreadth(length) , m_minTrackBreadthIsMinOrMaxContent(false) , m_minTrackBreadthIsMaxContent(false) , m_maxTrackBreadthIsMinOrMaxContent(false) , m_maxTrackBreadthIsMaxContent(false) { - // Someone has to set a valid lenght type through setLength or - // setMinMax before using the object. + cacheMinMaxTrackBreadthTypes(); } - GridTrackSize(LengthType type) - : m_type(LengthTrackSizing) - , m_minTrackBreadth(type) - , m_maxTrackBreadth(type) + GridTrackSize(const GridLength& minTrackBreadth, const GridLength& maxTrackBreadth) + : m_type(MinMaxTrackSizing) + , m_minTrackBreadth(minTrackBreadth) + , m_maxTrackBreadth(maxTrackBreadth) , m_minTrackBreadthIsMinOrMaxContent(false) , m_minTrackBreadthIsMaxContent(false) , m_maxTrackBreadthIsMinOrMaxContent(false) , m_maxTrackBreadthIsMaxContent(false) { - ASSERT(type != Undefined); - cacheMinMaxTrackBreadthTypes(); } @@ -74,24 +71,13 @@ public: ASSERT(m_type == LengthTrackSizing); ASSERT(m_minTrackBreadth == m_maxTrackBreadth); const GridLength& minTrackBreadth = m_minTrackBreadth; - ASSERT(!minTrackBreadth.isLength() || !minTrackBreadth.length().isUndefined()); return minTrackBreadth; } - void setLength(const GridLength& length) - { - m_type = LengthTrackSizing; - m_minTrackBreadth = length; - m_maxTrackBreadth = length; - - cacheMinMaxTrackBreadthTypes(); - } - const GridLength& minTrackBreadth() const { - ASSERT(!m_minTrackBreadth.isLength() || !m_minTrackBreadth.length().isUndefined()); if (m_minTrackBreadth.isLength() && m_minTrackBreadth.length().isAuto()) { - DEFINE_STATIC_LOCAL(GridLength, minContent, (MinContent)); + DEFINE_STATIC_LOCAL(GridLength, minContent, (Length(MinContent))); return minContent; } return m_minTrackBreadth; @@ -99,27 +85,19 @@ public: const GridLength& maxTrackBreadth() const { - ASSERT(!m_maxTrackBreadth.isLength() || !m_maxTrackBreadth.length().isUndefined()); if (m_maxTrackBreadth.isLength() && m_maxTrackBreadth.length().isAuto()) { - DEFINE_STATIC_LOCAL(GridLength, maxContent, (MaxContent)); + DEFINE_STATIC_LOCAL(GridLength, maxContent, (Length(MaxContent))); return maxContent; } return m_maxTrackBreadth; } - void setMinMax(const GridLength& minTrackBreadth, const GridLength& maxTrackBreadth) - { - m_type = MinMaxTrackSizing; - m_minTrackBreadth = minTrackBreadth; - m_maxTrackBreadth = maxTrackBreadth; - - cacheMinMaxTrackBreadthTypes(); - } - GridTrackSizeType type() const { return m_type; } bool isContentSized() const { return m_minTrackBreadth.isContentSized() || m_maxTrackBreadth.isContentSized(); } + bool isPercentage() const { return m_type == LengthTrackSizing && length().isLength() && length().length().isPercent(); } + bool operator==(const GridTrackSize& other) const { return m_type == other.m_type && m_minTrackBreadth == other.m_minTrackBreadth && m_maxTrackBreadth == other.m_maxTrackBreadth; diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/KeyframeList.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/KeyframeList.cpp index 2ed58360ee1..4ddaf8a5789 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/KeyframeList.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/KeyframeList.cpp @@ -28,27 +28,6 @@ namespace WebCore { -void KeyframeValue::addProperties(const StylePropertySet* propertySet) -{ - if (!propertySet) - return; - unsigned propertyCount = propertySet->propertyCount(); - for (unsigned i = 0; i < propertyCount; ++i) { - CSSPropertyID property = propertySet->propertyAt(i).id(); - // Timing-function within keyframes is special, because it is not animated; it just - // describes the timing function between this keyframe and the next. - if (property != CSSPropertyWebkitAnimationTimingFunction && property != CSSPropertyAnimationTimingFunction) - addProperty(property); - } -} - -TimingFunction* KeyframeValue::timingFunction(const RenderStyle& keyframeStyle) -{ - const CSSAnimationDataList* animations = keyframeStyle.animations(); - ASSERT(animations && !animations->isEmpty()); - return animations->animation(0)->timingFunction(); -} - KeyframeList::~KeyframeList() { clear(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/KeyframeList.h b/chromium/third_party/WebKit/Source/core/rendering/style/KeyframeList.h index ee2d237b505..26f7b9e76d7 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/KeyframeList.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/KeyframeList.h @@ -25,7 +25,7 @@ #ifndef KeyframeList_h #define KeyframeList_h -#include "CSSPropertyNames.h" +#include "core/CSSPropertyNames.h" #include "core/rendering/style/StyleInheritedData.h" #include "wtf/HashSet.h" #include "wtf/RefPtr.h" @@ -36,8 +36,6 @@ namespace WebCore { class RenderObject; class RenderStyle; -class StylePropertySet; -class TimingFunction; class KeyframeValue { public: @@ -47,7 +45,6 @@ public: { } - void addProperties(const StylePropertySet*); 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; } @@ -58,8 +55,6 @@ public: const RenderStyle* style() const { return m_style.get(); } void setStyle(PassRefPtr<RenderStyle> style) { m_style = style; } - static TimingFunction* timingFunction(const RenderStyle& keyframeStyle); - private: double m_key; HashSet<CSSPropertyID> m_properties; // The properties specified in this keyframe. @@ -71,8 +66,8 @@ public: KeyframeList(RenderObject&, const AtomicString& animationName) : m_animationName(animationName) { - insert(KeyframeValue(0, 0)); - insert(KeyframeValue(1, 0)); + insert(KeyframeValue(0, nullptr)); + insert(KeyframeValue(1, nullptr)); } ~KeyframeList(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/NinePieceImage.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/NinePieceImage.cpp index 383ca14283a..12c050849b1 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/NinePieceImage.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/NinePieceImage.cpp @@ -24,6 +24,8 @@ #include "config.h" #include "core/rendering/style/NinePieceImage.h" +#include "core/rendering/style/DataEquivalency.h" + namespace WebCore { static DataRef<NinePieceImageData>& defaultData() @@ -55,7 +57,7 @@ NinePieceImageData::NinePieceImageData() : fill(false) , horizontalRule(StretchImageRule) , verticalRule(StretchImageRule) - , image(0) + , image(nullptr) , imageSlices(Length(100, Percent), Length(100, Percent), Length(100, Percent), Length(100, Percent)) , borderSlices(1.0, 1.0, 1.0, 1.0) , outset(Length(0, Fixed), Length(0, Fixed), Length(0, Fixed), Length(0, Fixed)) @@ -76,7 +78,7 @@ NinePieceImageData::NinePieceImageData(const NinePieceImageData& other) bool NinePieceImageData::operator==(const NinePieceImageData& other) const { - return StyleImage::imagesEquivalent(image.get(), other.image.get()) + return dataEquivalent(image, other.image) && imageSlices == other.imageSlices && fill == other.fill && borderSlices == other.borderSlices diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/OutlineValue.h b/chromium/third_party/WebKit/Source/core/rendering/style/OutlineValue.h index ccf3c272a01..e70b23229e6 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/OutlineValue.h +++ b/chromium/third_party/WebKit/Source/core/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_colorIsValid == o.m_colorIsValid && m_offset == o.m_offset && m_isAuto == o.m_isAuto; + return BorderValue::operator==(o) && m_offset == o.m_offset && m_isAuto == o.m_isAuto; } bool operator!=(const OutlineValue& o) const diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/QuotesData.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/QuotesData.cpp index a6ef8e9e120..5ec5c0c9374 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/QuotesData.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/QuotesData.cpp @@ -64,13 +64,4 @@ const String QuotesData::getCloseQuote(int index) const return m_quotePairs.at(index).second; } -bool QuotesData::equals(const QuotesData* a, const QuotesData* b) -{ - if (a == b) - return true; - if (!a || !b) - return false; - return a->m_quotePairs == b->m_quotePairs; -} - } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/QuotesData.h b/chromium/third_party/WebKit/Source/core/rendering/style/QuotesData.h index 94e89e37e10..f8db17b82b9 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/QuotesData.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/QuotesData.h @@ -35,8 +35,8 @@ public: static PassRefPtr<QuotesData> create(const String open, const String close); static PassRefPtr<QuotesData> create(UChar open1, UChar close1, UChar open2, UChar close2); - // FIXME: this should be an operator==. - static bool equals(const QuotesData*, const QuotesData*); + bool operator==(const QuotesData& o) const { return m_quotePairs == o.m_quotePairs; } + bool operator!=(const QuotesData& o) const { return !(*this == o); } void addPair(const std::pair<String, String> quotePair); const String getOpenQuote(int index) const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/RenderStyle.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/RenderStyle.cpp index 2bbea394980..6b072146cfb 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/RenderStyle.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/RenderStyle.cpp @@ -24,18 +24,20 @@ #include "core/rendering/style/RenderStyle.h" #include <algorithm> -#include "RuntimeEnabledFeatures.h" #include "core/css/resolver/StyleResolver.h" #include "core/rendering/RenderTheme.h" #include "core/rendering/TextAutosizer.h" +#include "core/rendering/style/AppliedTextDecoration.h" #include "core/rendering/style/ContentData.h" -#include "core/rendering/style/CursorList.h" #include "core/rendering/style/QuotesData.h" #include "core/rendering/style/ShadowList.h" #include "core/rendering/style/StyleImage.h" #include "core/rendering/style/StyleInheritedData.h" +#include "platform/LengthFunctions.h" +#include "platform/RuntimeEnabledFeatures.h" #include "platform/fonts/Font.h" #include "platform/fonts/FontSelector.h" +#include "platform/geometry/FloatRoundedRect.h" #include "wtf/MathExtras.h" using namespace std; @@ -124,6 +126,7 @@ ALWAYS_INLINE RenderStyle::RenderStyle(DefaultStyleTag) rareNonInheritedData.access()->m_marquee.init(); rareNonInheritedData.access()->m_multiCol.init(); rareNonInheritedData.access()->m_transform.init(); + rareNonInheritedData.access()->m_willChange.init(); rareNonInheritedData.access()->m_filter.init(); rareNonInheritedData.access()->m_grid.init(); rareNonInheritedData.access()->m_gridItem.init(); @@ -147,7 +150,7 @@ ALWAYS_INLINE RenderStyle::RenderStyle(const RenderStyle& o) { } -static StyleRecalcChange comparePseudoStyles(const RenderStyle* oldStyle, const RenderStyle* newStyle) +static StyleRecalcChange diffPseudoStyles(const RenderStyle* oldStyle, const RenderStyle* newStyle) { // If the pseudoStyles have changed, we want any StyleRecalcChange that is not NoChange // because setStyle will do the right thing with anything else. @@ -166,7 +169,7 @@ static StyleRecalcChange comparePseudoStyles(const RenderStyle* oldStyle, const return NoChange; } -StyleRecalcChange RenderStyle::compare(const RenderStyle* oldStyle, const RenderStyle* newStyle) +StyleRecalcChange RenderStyle::stylePropagationDiff(const RenderStyle* oldStyle, const RenderStyle* newStyle) { if ((!oldStyle && newStyle) || (oldStyle && !newStyle)) return Reattach; @@ -177,15 +180,12 @@ StyleRecalcChange RenderStyle::compare(const RenderStyle* oldStyle, const Render if (oldStyle->display() != newStyle->display() || oldStyle->hasPseudoStyle(FIRST_LETTER) != newStyle->hasPseudoStyle(FIRST_LETTER) || oldStyle->columnSpan() != newStyle->columnSpan() - || oldStyle->specifiesAutoColumns() != newStyle->specifiesAutoColumns() || !oldStyle->contentDataEquivalent(newStyle) - || oldStyle->hasTextCombine() != newStyle->hasTextCombine() - || oldStyle->flowThread() != newStyle->flowThread() - || oldStyle->regionThread() != newStyle->regionThread()) + || oldStyle->hasTextCombine() != newStyle->hasTextCombine()) return Reattach; if (*oldStyle == *newStyle) - return comparePseudoStyles(oldStyle, newStyle); + return diffPseudoStyles(oldStyle, newStyle); if (oldStyle->inheritedNotEqual(newStyle) || oldStyle->hasExplicitlyInheritedProperties() @@ -233,6 +233,7 @@ void RenderStyle::copyNonInheritedFrom(const RenderStyle* other) noninherited_flags._page_break_inside = other->noninherited_flags._page_break_inside; noninherited_flags.explicitInheritance = other->noninherited_flags.explicitInheritance; noninherited_flags.currentColor = other->noninherited_flags.currentColor; + noninherited_flags.hasViewportUnits = other->noninherited_flags.hasViewportUnits; if (m_svgStyle != other->m_svgStyle) m_svgStyle.access()->copyNonInheritedFrom(other->m_svgStyle.get()); ASSERT(zoom() == initialZoom()); @@ -336,7 +337,7 @@ bool RenderStyle::inheritedDataShared(const RenderStyle* other) const && rareInheritedData.get() == other->rareInheritedData.get(); } -static bool positionedObjectMoved(const LengthBox& a, const LengthBox& b, const Length& width) +static bool positionedObjectMovedOnly(const LengthBox& a, const LengthBox& b, const Length& width) { // If any unit types are different, then we can't guarantee // that this was just a movement. @@ -353,9 +354,11 @@ static bool positionedObjectMoved(const LengthBox& a, const LengthBox& b, const return false; if (!a.top().isIntrinsicOrAuto() && !a.bottom().isIntrinsicOrAuto()) return false; - // If our width is auto and left or right is specified then this + // If our width is auto and left or right is specified and changed then this // is not just a movement - we need to resize to our container. - if ((!a.left().isIntrinsicOrAuto() || !a.right().isIntrinsicOrAuto()) && width.isIntrinsicOrAuto()) + if (width.isIntrinsicOrAuto() + && ((!a.left().isIntrinsicOrAuto() && a.left() != b.left()) + || (!a.right().isIntrinsicOrAuto() && a.right() != b.right()))) return false; // One of the units is fixed or percent in both directions and stayed @@ -363,328 +366,364 @@ static bool positionedObjectMoved(const LengthBox& a, const LengthBox& b, const return true; } -StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const +StyleDifference RenderStyle::visualInvalidationDiff(const RenderStyle& other, unsigned& changedContextSensitiveProperties) const { - changedContextSensitiveProperties = ContextSensitivePropertyNone; + // Note, we use .get() on each DataRef below because DataRef::operator== will do a deep + // compare, which is duplicate work when we're going to compare each property inside + // this function anyway. - StyleDifference svgChange = StyleDifferenceEqual; - if (m_svgStyle != other->m_svgStyle) { - svgChange = m_svgStyle->diff(other->m_svgStyle.get()); - if (svgChange == StyleDifferenceLayout) - return svgChange; + StyleDifference diff; + if (m_svgStyle.get() != other.m_svgStyle.get()) + diff = m_svgStyle->diff(other.m_svgStyle.get()); + + if ((!diff.needsFullLayout() || !diff.needsRepaint()) && diffNeedsFullLayoutAndRepaint(other)) { + diff.setNeedsFullLayout(); + diff.setNeedsRepaintObject(); + } + + if (!diff.needsFullLayout() && diffNeedsFullLayout(other)) + diff.setNeedsFullLayout(); + + if (!diff.needsFullLayout() && position() != StaticPosition && surround->offset != other.surround->offset) { + // Optimize for the case where a positioned layer is moving but not changing size. + if ((position() == AbsolutePosition || position() == FixedPosition) + && positionedObjectMovedOnly(surround->offset, other.surround->offset, m_box->width())) { + diff.setNeedsPositionedMovementLayout(); + } else { + // FIXME: We would like to use SimplifiedLayout for relative positioning, but we can't quite do that yet. + // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need + // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line). + diff.setNeedsFullLayout(); + } + } + + if (diffNeedsRepaintLayer(other)) + diff.setNeedsRepaintLayer(); + else if (diffNeedsRepaintObject(other)) + diff.setNeedsRepaintObject(); + + changedContextSensitiveProperties = computeChangedContextSensitiveProperties(other, diff); + + if (diff.hasNoChange() && diffNeedsRecompositeLayer(other)) + diff.setNeedsRecompositeLayer(); + + // Cursors are not checked, since they will be set appropriately in response to mouse events, + // so they don't need to cause any repaint or layout. + + // Animations don't need to be checked either. We always set the new style on the RenderObject, so we will get a chance to fire off + // the resulting transition properly. + + return diff; +} + +bool RenderStyle::diffNeedsFullLayoutAndRepaint(const RenderStyle& other) const +{ + // FIXME: Not all cases in this method need both full layout and repaint. + // Should move cases into diffNeedsFullLayout() if + // - don't need repaint at all; + // - or the renderer knows how to exactly repaint caused by the layout change + // instead of forced full repaint. + + if (m_box.get() != other.m_box.get()) { + if (m_box->width() != other.m_box->width() + || m_box->minWidth() != other.m_box->minWidth() + || m_box->maxWidth() != other.m_box->maxWidth() + || m_box->height() != other.m_box->height() + || m_box->minHeight() != other.m_box->minHeight() + || m_box->maxHeight() != other.m_box->maxHeight()) + return true; + + if (m_box->verticalAlign() != other.m_box->verticalAlign()) + return true; + + if (m_box->boxSizing() != other.m_box->boxSizing()) + return true; + } + + if (surround.get() != other.surround.get()) { + if (surround->margin != other.surround->margin) + return true; + + if (surround->padding != other.surround->padding) + return true; + + // If our border widths change, then we need to layout. Other changes to borders only necessitate a repaint. + if (borderLeftWidth() != other.borderLeftWidth() + || borderTopWidth() != other.borderTopWidth() + || borderBottomWidth() != other.borderBottomWidth() + || borderRightWidth() != other.borderRightWidth()) + return true; } - if (m_box->width() != other->m_box->width() - || m_box->minWidth() != other->m_box->minWidth() - || m_box->maxWidth() != other->m_box->maxWidth() - || m_box->height() != other->m_box->height() - || m_box->minHeight() != other->m_box->minHeight() - || m_box->maxHeight() != other->m_box->maxHeight()) - return StyleDifferenceLayout; - - if (m_box->verticalAlign() != other->m_box->verticalAlign() || noninherited_flags._vertical_align != other->noninherited_flags._vertical_align) - return StyleDifferenceLayout; - - if (m_box->boxSizing() != other->m_box->boxSizing()) - return StyleDifferenceLayout; - - if (surround->margin != other->surround->margin) - return StyleDifferenceLayout; - - if (surround->padding != other->surround->padding) - return StyleDifferenceLayout; - - if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { - if (rareNonInheritedData->m_appearance != other->rareNonInheritedData->m_appearance - || rareNonInheritedData->marginBeforeCollapse != other->rareNonInheritedData->marginBeforeCollapse - || rareNonInheritedData->marginAfterCollapse != other->rareNonInheritedData->marginAfterCollapse - || rareNonInheritedData->lineClamp != other->rareNonInheritedData->lineClamp - || rareNonInheritedData->textOverflow != other->rareNonInheritedData->textOverflow) - return StyleDifferenceLayout; - - if (rareNonInheritedData->m_regionFragment != other->rareNonInheritedData->m_regionFragment) - return StyleDifferenceLayout; - - if (rareNonInheritedData->m_wrapFlow != other->rareNonInheritedData->m_wrapFlow - || rareNonInheritedData->m_wrapThrough != other->rareNonInheritedData->m_wrapThrough - || rareNonInheritedData->m_shapeMargin != other->rareNonInheritedData->m_shapeMargin - || rareNonInheritedData->m_shapePadding != other->rareNonInheritedData->m_shapePadding) - return StyleDifferenceLayout; - - if (rareNonInheritedData->m_deprecatedFlexibleBox.get() != other->rareNonInheritedData->m_deprecatedFlexibleBox.get() - && *rareNonInheritedData->m_deprecatedFlexibleBox.get() != *other->rareNonInheritedData->m_deprecatedFlexibleBox.get()) - return StyleDifferenceLayout; - - if (rareNonInheritedData->m_flexibleBox.get() != other->rareNonInheritedData->m_flexibleBox.get() - && *rareNonInheritedData->m_flexibleBox.get() != *other->rareNonInheritedData->m_flexibleBox.get()) - return StyleDifferenceLayout; - if (rareNonInheritedData->m_order != other->rareNonInheritedData->m_order - || rareNonInheritedData->m_alignContent != other->rareNonInheritedData->m_alignContent - || rareNonInheritedData->m_alignItems != other->rareNonInheritedData->m_alignItems - || rareNonInheritedData->m_alignSelf != other->rareNonInheritedData->m_alignSelf - || rareNonInheritedData->m_justifyContent != other->rareNonInheritedData->m_justifyContent) - return StyleDifferenceLayout; + if (rareNonInheritedData.get() != other.rareNonInheritedData.get()) { + if (rareNonInheritedData->m_appearance != other.rareNonInheritedData->m_appearance + || rareNonInheritedData->marginBeforeCollapse != other.rareNonInheritedData->marginBeforeCollapse + || rareNonInheritedData->marginAfterCollapse != other.rareNonInheritedData->marginAfterCollapse + || rareNonInheritedData->lineClamp != other.rareNonInheritedData->lineClamp + || rareNonInheritedData->textOverflow != other.rareNonInheritedData->textOverflow + || rareNonInheritedData->m_wrapFlow != other.rareNonInheritedData->m_wrapFlow + || rareNonInheritedData->m_wrapThrough != other.rareNonInheritedData->m_wrapThrough + || rareNonInheritedData->m_shapeMargin != other.rareNonInheritedData->m_shapeMargin + || rareNonInheritedData->m_order != other.rareNonInheritedData->m_order + || rareNonInheritedData->m_alignContent != other.rareNonInheritedData->m_alignContent + || rareNonInheritedData->m_alignItems != other.rareNonInheritedData->m_alignItems + || rareNonInheritedData->m_alignSelf != other.rareNonInheritedData->m_alignSelf + || rareNonInheritedData->m_justifyContent != other.rareNonInheritedData->m_justifyContent + || rareNonInheritedData->m_grid.get() != other.rareNonInheritedData->m_grid.get() + || rareNonInheritedData->m_gridItem.get() != other.rareNonInheritedData->m_gridItem.get() + || rareNonInheritedData->m_textCombine != other.rareNonInheritedData->m_textCombine + || rareNonInheritedData->hasFilters() != other.rareNonInheritedData->hasFilters()) + return true; + + if (rareNonInheritedData->m_deprecatedFlexibleBox.get() != other.rareNonInheritedData->m_deprecatedFlexibleBox.get() + && *rareNonInheritedData->m_deprecatedFlexibleBox.get() != *other.rareNonInheritedData->m_deprecatedFlexibleBox.get()) + return true; + + if (rareNonInheritedData->m_flexibleBox.get() != other.rareNonInheritedData->m_flexibleBox.get() + && *rareNonInheritedData->m_flexibleBox.get() != *other.rareNonInheritedData->m_flexibleBox.get()) + return true; // FIXME: We should add an optimized form of layout that just recomputes visual overflow. - if (!rareNonInheritedData->shadowDataEquivalent(*other->rareNonInheritedData.get())) - return StyleDifferenceLayout; + if (!rareNonInheritedData->shadowDataEquivalent(*other.rareNonInheritedData.get())) + return true; + + if (!rareNonInheritedData->reflectionDataEquivalent(*other.rareNonInheritedData.get())) + return true; - if (!rareNonInheritedData->reflectionDataEquivalent(*other->rareNonInheritedData.get())) - return StyleDifferenceLayout; + if (rareNonInheritedData->m_multiCol.get() != other.rareNonInheritedData->m_multiCol.get() + && *rareNonInheritedData->m_multiCol.get() != *other.rareNonInheritedData->m_multiCol.get()) + return true; - if (rareNonInheritedData->m_multiCol.get() != other->rareNonInheritedData->m_multiCol.get() - && *rareNonInheritedData->m_multiCol.get() != *other->rareNonInheritedData->m_multiCol.get()) - return StyleDifferenceLayout; + // If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree. + const CounterDirectiveMap* mapA = rareNonInheritedData->m_counterDirectives.get(); + const CounterDirectiveMap* mapB = other.rareNonInheritedData->m_counterDirectives.get(); + if (!(mapA == mapB || (mapA && mapB && *mapA == *mapB))) + return true; - if (rareNonInheritedData->m_transform.get() != other->rareNonInheritedData->m_transform.get() - && *rareNonInheritedData->m_transform.get() != *other->rareNonInheritedData->m_transform.get()) { - // Don't return early here; instead take note of the type of - // change, and deal with it when looking at compositing. - changedContextSensitiveProperties |= ContextSensitivePropertyTransform; + // We only need do layout for opacity changes if adding or losing opacity could trigger a change + // in us being a stacking context. + if (hasAutoZIndex() != other.hasAutoZIndex() && rareNonInheritedData->hasOpacity() != other.rareNonInheritedData->hasOpacity()) { + // FIXME: We would like to use SimplifiedLayout here, but we can't quite do that yet. + // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need + // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line). + // In addition we need to solve the floating object issue when layers come and go. Right now + // a full layout is necessary to keep floating object lists sane. + return true; } + } - if (rareNonInheritedData->m_grid.get() != other->rareNonInheritedData->m_grid.get() - || rareNonInheritedData->m_gridItem.get() != other->rareNonInheritedData->m_gridItem.get()) - return StyleDifferenceLayout; + if (rareInheritedData.get() != other.rareInheritedData.get()) { + if (rareInheritedData->highlight != other.rareInheritedData->highlight + || rareInheritedData->indent != other.rareInheritedData->indent + || rareInheritedData->m_textAlignLast != other.rareInheritedData->m_textAlignLast + || rareInheritedData->m_textIndentLine != other.rareInheritedData->m_textIndentLine + || rareInheritedData->m_effectiveZoom != other.rareInheritedData->m_effectiveZoom + || rareInheritedData->wordBreak != other.rareInheritedData->wordBreak + || rareInheritedData->overflowWrap != other.rareInheritedData->overflowWrap + || rareInheritedData->lineBreak != other.rareInheritedData->lineBreak + || rareInheritedData->textSecurity != other.rareInheritedData->textSecurity + || rareInheritedData->hyphens != other.rareInheritedData->hyphens + || rareInheritedData->hyphenationLimitBefore != other.rareInheritedData->hyphenationLimitBefore + || rareInheritedData->hyphenationLimitAfter != other.rareInheritedData->hyphenationLimitAfter + || rareInheritedData->hyphenationString != other.rareInheritedData->hyphenationString + || rareInheritedData->locale != other.rareInheritedData->locale + || rareInheritedData->m_rubyPosition != other.rareInheritedData->m_rubyPosition + || rareInheritedData->textEmphasisMark != other.rareInheritedData->textEmphasisMark + || rareInheritedData->textEmphasisPosition != other.rareInheritedData->textEmphasisPosition + || rareInheritedData->textEmphasisCustomMark != other.rareInheritedData->textEmphasisCustomMark + || rareInheritedData->m_textJustify != other.rareInheritedData->m_textJustify + || rareInheritedData->m_textOrientation != other.rareInheritedData->m_textOrientation + || rareInheritedData->m_tabSize != other.rareInheritedData->m_tabSize + || rareInheritedData->m_lineBoxContain != other.rareInheritedData->m_lineBoxContain + || rareInheritedData->listStyleImage != other.rareInheritedData->listStyleImage + || rareInheritedData->textStrokeWidth != other.rareInheritedData->textStrokeWidth) + return true; - if (rareNonInheritedData->m_shapeInside != other->rareNonInheritedData->m_shapeInside) - return StyleDifferenceLayout; - } + if (!rareInheritedData->shadowDataEquivalent(*other.rareInheritedData.get())) + return true; - if (rareInheritedData.get() != other->rareInheritedData.get()) { - if (rareInheritedData->highlight != other->rareInheritedData->highlight - || rareInheritedData->indent != other->rareInheritedData->indent - || rareInheritedData->m_textAlignLast != other->rareInheritedData->m_textAlignLast - || rareInheritedData->m_textIndentLine != other->rareInheritedData->m_textIndentLine - || rareInheritedData->m_effectiveZoom != other->rareInheritedData->m_effectiveZoom - || rareInheritedData->wordBreak != other->rareInheritedData->wordBreak - || rareInheritedData->overflowWrap != other->rareInheritedData->overflowWrap - || rareInheritedData->lineBreak != other->rareInheritedData->lineBreak - || rareInheritedData->textSecurity != other->rareInheritedData->textSecurity - || rareInheritedData->hyphens != other->rareInheritedData->hyphens - || rareInheritedData->hyphenationLimitBefore != other->rareInheritedData->hyphenationLimitBefore - || rareInheritedData->hyphenationLimitAfter != other->rareInheritedData->hyphenationLimitAfter - || rareInheritedData->hyphenationString != other->rareInheritedData->hyphenationString - || rareInheritedData->locale != other->rareInheritedData->locale - || rareInheritedData->m_rubyPosition != other->rareInheritedData->m_rubyPosition - || rareInheritedData->textEmphasisMark != other->rareInheritedData->textEmphasisMark - || rareInheritedData->textEmphasisPosition != other->rareInheritedData->textEmphasisPosition - || rareInheritedData->textEmphasisCustomMark != other->rareInheritedData->textEmphasisCustomMark - || rareInheritedData->m_textAlignLast != other->rareInheritedData->m_textAlignLast - || rareInheritedData->m_textJustify != other->rareInheritedData->m_textJustify - || rareInheritedData->m_textOrientation != other->rareInheritedData->m_textOrientation - || rareInheritedData->m_tabSize != other->rareInheritedData->m_tabSize - || rareInheritedData->m_lineBoxContain != other->rareInheritedData->m_lineBoxContain - || rareInheritedData->m_lineGrid != other->rareInheritedData->m_lineGrid - || rareInheritedData->m_lineSnap != other->rareInheritedData->m_lineSnap - || rareInheritedData->m_lineAlign != other->rareInheritedData->m_lineAlign - || rareInheritedData->listStyleImage != other->rareInheritedData->listStyleImage) - return StyleDifferenceLayout; - - if (!rareInheritedData->shadowDataEquivalent(*other->rareInheritedData.get())) - return StyleDifferenceLayout; - - if (textStrokeWidth() != other->textStrokeWidth()) - return StyleDifferenceLayout; + if (!rareInheritedData->quotesDataEquivalent(*other.rareInheritedData.get())) + return true; } - if (visual->m_textAutosizingMultiplier != other->visual->m_textAutosizingMultiplier) - return StyleDifferenceLayout; + if (inherited->textAutosizingMultiplier != other.inherited->textAutosizingMultiplier) + return true; - if (inherited->line_height != other->inherited->line_height - || inherited->font != other->inherited->font - || inherited->horizontal_border_spacing != other->inherited->horizontal_border_spacing - || inherited->vertical_border_spacing != other->inherited->vertical_border_spacing - || inherited_flags._box_direction != other->inherited_flags._box_direction - || inherited_flags.m_rtlOrdering != other->inherited_flags.m_rtlOrdering - || noninherited_flags._position != other->noninherited_flags._position - || noninherited_flags._floating != other->noninherited_flags._floating - || noninherited_flags._originalDisplay != other->noninherited_flags._originalDisplay) - return StyleDifferenceLayout; + if (inherited.get() != other.inherited.get()) { + if (inherited->line_height != other.inherited->line_height + || inherited->font != other.inherited->font + || inherited->horizontal_border_spacing != other.inherited->horizontal_border_spacing + || inherited->vertical_border_spacing != other.inherited->vertical_border_spacing) + return true; + } + if (inherited_flags._box_direction != other.inherited_flags._box_direction + || inherited_flags.m_rtlOrdering != other.inherited_flags.m_rtlOrdering + || inherited_flags._text_align != other.inherited_flags._text_align + || inherited_flags._text_transform != other.inherited_flags._text_transform + || inherited_flags._direction != other.inherited_flags._direction + || inherited_flags._white_space != other.inherited_flags._white_space + || inherited_flags.m_writingMode != other.inherited_flags.m_writingMode) + return true; - if (((int)noninherited_flags._effectiveDisplay) >= TABLE) { - if (inherited_flags._border_collapse != other->inherited_flags._border_collapse - || inherited_flags._empty_cells != other->inherited_flags._empty_cells - || inherited_flags._caption_side != other->inherited_flags._caption_side - || noninherited_flags._table_layout != other->noninherited_flags._table_layout) - return StyleDifferenceLayout; + if (noninherited_flags._overflowX != other.noninherited_flags._overflowX + || noninherited_flags._overflowY != other.noninherited_flags._overflowY + || noninherited_flags._clear != other.noninherited_flags._clear + || noninherited_flags._unicodeBidi != other.noninherited_flags._unicodeBidi + || noninherited_flags._position != other.noninherited_flags._position + || noninherited_flags._floating != other.noninherited_flags._floating + || noninherited_flags._originalDisplay != other.noninherited_flags._originalDisplay + || noninherited_flags._vertical_align != other.noninherited_flags._vertical_align) + return true; + + if (noninherited_flags._effectiveDisplay >= FIRST_TABLE_DISPLAY && noninherited_flags._effectiveDisplay <= LAST_TABLE_DISPLAY) { + if (inherited_flags._border_collapse != other.inherited_flags._border_collapse + || inherited_flags._empty_cells != other.inherited_flags._empty_cells + || inherited_flags._caption_side != other.inherited_flags._caption_side + || noninherited_flags._table_layout != other.noninherited_flags._table_layout) + return true; // In the collapsing border model, 'hidden' suppresses other borders, while 'none' // does not, so these style differences can be width differences. if (inherited_flags._border_collapse - && ((borderTopStyle() == BHIDDEN && other->borderTopStyle() == BNONE) - || (borderTopStyle() == BNONE && other->borderTopStyle() == BHIDDEN) - || (borderBottomStyle() == BHIDDEN && other->borderBottomStyle() == BNONE) - || (borderBottomStyle() == BNONE && other->borderBottomStyle() == BHIDDEN) - || (borderLeftStyle() == BHIDDEN && other->borderLeftStyle() == BNONE) - || (borderLeftStyle() == BNONE && other->borderLeftStyle() == BHIDDEN) - || (borderRightStyle() == BHIDDEN && other->borderRightStyle() == BNONE) - || (borderRightStyle() == BNONE && other->borderRightStyle() == BHIDDEN))) - return StyleDifferenceLayout; + && ((borderTopStyle() == BHIDDEN && other.borderTopStyle() == BNONE) + || (borderTopStyle() == BNONE && other.borderTopStyle() == BHIDDEN) + || (borderBottomStyle() == BHIDDEN && other.borderBottomStyle() == BNONE) + || (borderBottomStyle() == BNONE && other.borderBottomStyle() == BHIDDEN) + || (borderLeftStyle() == BHIDDEN && other.borderLeftStyle() == BNONE) + || (borderLeftStyle() == BNONE && other.borderLeftStyle() == BHIDDEN) + || (borderRightStyle() == BHIDDEN && other.borderRightStyle() == BNONE) + || (borderRightStyle() == BNONE && other.borderRightStyle() == BHIDDEN))) + return true; + } else if (noninherited_flags._effectiveDisplay == LIST_ITEM) { + if (inherited_flags._list_style_type != other.inherited_flags._list_style_type + || inherited_flags._list_style_position != other.inherited_flags._list_style_position) + return true; } - if (noninherited_flags._effectiveDisplay == LIST_ITEM) { - if (inherited_flags._list_style_type != other->inherited_flags._list_style_type - || inherited_flags._list_style_position != other->inherited_flags._list_style_position) - return StyleDifferenceLayout; - } + if ((visibility() == COLLAPSE) != (other.visibility() == COLLAPSE)) + return true; - if (inherited_flags._text_align != other->inherited_flags._text_align - || inherited_flags._text_transform != other->inherited_flags._text_transform - || inherited_flags._direction != other->inherited_flags._direction - || inherited_flags._white_space != other->inherited_flags._white_space - || noninherited_flags._clear != other->noninherited_flags._clear - || noninherited_flags._unicodeBidi != other->noninherited_flags._unicodeBidi) - return StyleDifferenceLayout; - - // Check block flow direction. - if (inherited_flags.m_writingMode != other->inherited_flags.m_writingMode) - return StyleDifferenceLayout; - - // Check text combine mode. - if (rareNonInheritedData->m_textCombine != other->rareNonInheritedData->m_textCombine) - return StyleDifferenceLayout; - - // Overflow returns a layout hint. - if (noninherited_flags._overflowX != other->noninherited_flags._overflowX - || noninherited_flags._overflowY != other->noninherited_flags._overflowY) - return StyleDifferenceLayout; - - // If our border widths change, then we need to layout. Other changes to borders - // only necessitate a repaint. - if (borderLeftWidth() != other->borderLeftWidth() - || borderTopWidth() != other->borderTopWidth() - || borderBottomWidth() != other->borderBottomWidth() - || borderRightWidth() != other->borderRightWidth()) - return StyleDifferenceLayout; - - // If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree. - const CounterDirectiveMap* mapA = rareNonInheritedData->m_counterDirectives.get(); - const CounterDirectiveMap* mapB = other->rareNonInheritedData->m_counterDirectives.get(); - if (!(mapA == mapB || (mapA && mapB && *mapA == *mapB))) - return StyleDifferenceLayout; - - if ((visibility() == COLLAPSE) != (other->visibility() == COLLAPSE)) - return StyleDifferenceLayout; - - if (rareNonInheritedData->hasOpacity() != other->rareNonInheritedData->hasOpacity()) { - // FIXME: We would like to use SimplifiedLayout here, but we can't quite do that yet. - // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need - // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line). - // In addition we need to solve the floating object issue when layers come and go. Right now - // a full layout is necessary to keep floating object lists sane. - return StyleDifferenceLayout; + if (!m_background->outline().visuallyEqual(other.m_background->outline())) { + // FIXME: We only really need to recompute the overflow but we don't have an optimized layout for it. + return true; } - if (rareNonInheritedData->hasFilters() != other->rareNonInheritedData->hasFilters()) - return StyleDifferenceLayout; + // Movement of non-static-positioned object is special cased in RenderStyle::visualInvalidationDiff(). - if (!QuotesData::equals(rareInheritedData->quotes.get(), other->rareInheritedData->quotes.get())) - return StyleDifferenceLayout; + return false; +} + +bool RenderStyle::diffNeedsFullLayout(const RenderStyle& other) const +{ + return false; +} - // SVGRenderStyle::diff() might have returned StyleDifferenceRepaint, eg. if fill changes. - // If eg. the font-size changed at the same time, we're not allowed to return StyleDifferenceRepaint, - // but have to return StyleDifferenceLayout, that's why this if branch comes after all branches - // that are relevant for SVG and might return StyleDifferenceLayout. - if (svgChange != StyleDifferenceEqual) - return svgChange; +bool RenderStyle::diffNeedsRepaintLayer(const RenderStyle& other) const +{ + if (position() != StaticPosition && (visual->clip != other.visual->clip || visual->hasClip != other.visual->hasClip)) + return true; - // Make sure these left/top/right/bottom checks stay below all layout checks and above - // all visible checks. - if (position() != StaticPosition && surround->offset != other->surround->offset) { - // Optimize for the case where a positioned layer is moving but not changing size. - if (position() == AbsolutePosition && positionedObjectMoved(surround->offset, other->surround->offset, m_box->width()) && repaintOnlyDiff(other, changedContextSensitiveProperties) == StyleDifferenceEqual) - return StyleDifferenceLayoutPositionedMovementOnly; + if (rareNonInheritedData.get() != other.rareNonInheritedData.get()) { + if (RuntimeEnabledFeatures::cssCompositingEnabled() + && (rareNonInheritedData->m_effectiveBlendMode != other.rareNonInheritedData->m_effectiveBlendMode + || rareNonInheritedData->m_isolation != other.rareNonInheritedData->m_isolation)) + return true; - // FIXME: We would like to use SimplifiedLayout for relative positioning, but we can't quite do that yet. - // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need - // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line). - return StyleDifferenceLayout; + if (rareNonInheritedData->m_mask != other.rareNonInheritedData->m_mask + || rareNonInheritedData->m_maskBoxImage != other.rareNonInheritedData->m_maskBoxImage) + return true; } - return repaintOnlyDiff(other, changedContextSensitiveProperties); + + return false; } -StyleDifference RenderStyle::repaintOnlyDiff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const +bool RenderStyle::diffNeedsRepaintObject(const RenderStyle& other) const { - if (position() != StaticPosition && (m_box->zIndex() != other->m_box->zIndex() || m_box->hasAutoZIndex() != other->m_box->hasAutoZIndex() - || visual->clip != other->visual->clip || visual->hasClip != other->visual->hasClip)) - return StyleDifferenceRepaintLayer; - - if (RuntimeEnabledFeatures::cssCompositingEnabled() && rareNonInheritedData->m_effectiveBlendMode != other->rareNonInheritedData->m_effectiveBlendMode) - return StyleDifferenceRepaintLayer; + if (inherited_flags._visibility != other.inherited_flags._visibility + || inherited_flags.m_printColorAdjust != other.inherited_flags.m_printColorAdjust + || inherited_flags._insideLink != other.inherited_flags._insideLink + || !surround->border.visuallyEqual(other.surround->border) + || !m_background->visuallyEqual(*other.m_background)) + return true; - if (rareNonInheritedData->opacity != other->rareNonInheritedData->opacity) { - // Don't return early here; instead take note of the type of change, - // and deal with it when looking at compositing. - changedContextSensitiveProperties |= ContextSensitivePropertyOpacity; + if (rareInheritedData.get() != other.rareInheritedData.get()) { + if (rareInheritedData->userModify != other.rareInheritedData->userModify + || rareInheritedData->userSelect != other.rareInheritedData->userSelect + || rareInheritedData->m_imageRendering != other.rareInheritedData->m_imageRendering) + return true; } - if (rareNonInheritedData->m_filter.get() != other->rareNonInheritedData->m_filter.get() - && *rareNonInheritedData->m_filter.get() != *other->rareNonInheritedData->m_filter.get()) { - // Don't return early here; instead take note of the type of change, - // and deal with it when looking at compositing. - changedContextSensitiveProperties |= ContextSensitivePropertyFilter; + if (rareNonInheritedData.get() != other.rareNonInheritedData.get()) { + if (rareNonInheritedData->userDrag != other.rareNonInheritedData->userDrag + || rareNonInheritedData->m_borderFit != other.rareNonInheritedData->m_borderFit + || rareNonInheritedData->m_objectFit != other.rareNonInheritedData->m_objectFit + || rareNonInheritedData->m_objectPosition != other.rareNonInheritedData->m_objectPosition + || rareNonInheritedData->m_shapeOutside != other.rareNonInheritedData->m_shapeOutside + || rareNonInheritedData->m_clipPath != other.rareNonInheritedData->m_clipPath) + return true; } - if (rareNonInheritedData->m_mask != other->rareNonInheritedData->m_mask - || rareNonInheritedData->m_maskBoxImage != other->rareNonInheritedData->m_maskBoxImage) - return StyleDifferenceRepaintLayer; - - if (inherited_flags._visibility != other->inherited_flags._visibility - || inherited_flags.m_printColorAdjust != other->inherited_flags.m_printColorAdjust - || inherited_flags._insideLink != other->inherited_flags._insideLink - || surround->border != other->surround->border - || *m_background.get() != *other->m_background.get() - || rareInheritedData->userModify != other->rareInheritedData->userModify - || rareInheritedData->userSelect != other->rareInheritedData->userSelect - || rareNonInheritedData->userDrag != other->rareNonInheritedData->userDrag - || rareNonInheritedData->m_borderFit != other->rareNonInheritedData->m_borderFit - || rareNonInheritedData->m_objectFit != other->rareNonInheritedData->m_objectFit - || rareNonInheritedData->m_objectPosition != other->rareNonInheritedData->m_objectPosition - || rareInheritedData->m_imageRendering != other->rareInheritedData->m_imageRendering) - return StyleDifferenceRepaint; - - // FIXME: The current spec is being reworked to remove dependencies between exclusions and affected - // content. There's a proposal to use floats instead. In that case, wrap-shape should actually relayout - // the parent container. For sure, I will have to revisit this code, but for now I've added this in order - // to avoid having diff() == StyleDifferenceEqual where wrap-shapes actually differ. - // Tracking bug: https://bugs.webkit.org/show_bug.cgi?id=62991 - if (rareNonInheritedData->m_shapeOutside != other->rareNonInheritedData->m_shapeOutside) - return StyleDifferenceRepaint; - - if (rareNonInheritedData->m_clipPath != other->rareNonInheritedData->m_clipPath) - return StyleDifferenceRepaint; - - if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { - if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D - || rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility - || rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective - || rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX - || rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY) - return StyleDifferenceRecompositeLayer; + return false; +} + +bool RenderStyle::diffNeedsRecompositeLayer(const RenderStyle& other) const +{ + if (rareNonInheritedData.get() != other.rareNonInheritedData.get()) { + if (rareNonInheritedData->m_transformStyle3D != other.rareNonInheritedData->m_transformStyle3D + || rareNonInheritedData->m_backfaceVisibility != other.rareNonInheritedData->m_backfaceVisibility + || rareNonInheritedData->m_perspective != other.rareNonInheritedData->m_perspective + || rareNonInheritedData->m_perspectiveOriginX != other.rareNonInheritedData->m_perspectiveOriginX + || rareNonInheritedData->m_perspectiveOriginY != other.rareNonInheritedData->m_perspectiveOriginY + || hasWillChangeCompositingHint() != other.hasWillChangeCompositingHint()) + return true; } - if (inherited->color != other->inherited->color - || inherited_flags._text_decorations != other->inherited_flags._text_decorations - || visual->textDecoration != other->visual->textDecoration - || rareNonInheritedData->m_textDecorationStyle != other->rareNonInheritedData->m_textDecorationStyle - || rareNonInheritedData->m_textDecorationColor != other->rareNonInheritedData->m_textDecorationColor - || rareInheritedData->textFillColor != other->rareInheritedData->textFillColor - || rareInheritedData->textStrokeColor != other->rareInheritedData->textStrokeColor - || rareInheritedData->textEmphasisColor != other->rareInheritedData->textEmphasisColor - || rareInheritedData->textEmphasisFill != other->rareInheritedData->textEmphasisFill) - return StyleDifferenceRepaintIfTextOrColorChange; + return false; +} - // Cursors are not checked, since they will be set appropriately in response to mouse events, - // so they don't need to cause any repaint or layout. +unsigned RenderStyle::computeChangedContextSensitiveProperties(const RenderStyle& other, StyleDifference diff) const +{ + unsigned changedContextSensitiveProperties = ContextSensitivePropertyNone; - // Animations don't need to be checked either. We always set the new style on the RenderObject, so we will get a chance to fire off - // the resulting transition properly. - return StyleDifferenceEqual; + // StyleAdjuster has ensured that zIndex is non-auto only if it's applicable. + if (m_box->zIndex() != other.m_box->zIndex() || m_box->hasAutoZIndex() != other.m_box->hasAutoZIndex()) + changedContextSensitiveProperties |= ContextSensitivePropertyZIndex; + + if (rareNonInheritedData.get() != other.rareNonInheritedData.get()) { + if (!transformDataEquivalent(other)) + changedContextSensitiveProperties |= ContextSensitivePropertyTransform; + + if (rareNonInheritedData->opacity != other.rareNonInheritedData->opacity) + changedContextSensitiveProperties |= ContextSensitivePropertyOpacity; + + if (rareNonInheritedData->m_filter != other.rareNonInheritedData->m_filter) + changedContextSensitiveProperties |= ContextSensitivePropertyFilter; + } + + if (!diff.needsRepaint()) { + if (inherited->color != other.inherited->color + || inherited_flags.m_textUnderline != other.inherited_flags.m_textUnderline + || visual->textDecoration != other.visual->textDecoration) { + changedContextSensitiveProperties |= ContextSensitivePropertyTextOrColor; + } else if (rareNonInheritedData.get() != other.rareNonInheritedData.get()) { + if (rareNonInheritedData->m_textDecorationStyle != other.rareNonInheritedData->m_textDecorationStyle + || rareNonInheritedData->m_textDecorationColor != other.rareNonInheritedData->m_textDecorationColor) + changedContextSensitiveProperties |= ContextSensitivePropertyTextOrColor; + } else if (rareInheritedData.get() != other.rareInheritedData.get()) { + if (rareInheritedData->textFillColor() != other.rareInheritedData->textFillColor() + || rareInheritedData->textStrokeColor() != other.rareInheritedData->textStrokeColor() + || rareInheritedData->textEmphasisColor() != other.rareInheritedData->textEmphasisColor() + || rareInheritedData->textEmphasisFill != other.rareInheritedData->textEmphasisFill + || rareInheritedData->appliedTextDecorations != other.rareInheritedData->appliedTextDecorations) + changedContextSensitiveProperties |= ContextSensitivePropertyTextOrColor; + } + } + + return changedContextSensitiveProperties; } -void RenderStyle::setClip(Length top, Length right, Length bottom, Length left) +void RenderStyle::setClip(const Length& top, const Length& right, const Length& bottom, const Length& left) { StyleVisualData* data = visual.access(); data->clip.m_top = top; @@ -707,15 +746,13 @@ void RenderStyle::setCursorList(PassRefPtr<CursorList> other) void RenderStyle::setQuotes(PassRefPtr<QuotesData> q) { - if (QuotesData::equals(rareInheritedData->quotes.get(), q.get())) - return; rareInheritedData.access()->quotes = q; } void RenderStyle::clearCursorList() { if (rareInheritedData->cursorData) - rareInheritedData.access()->cursorData = 0; + rareInheritedData.access()->cursorData = nullptr; } void RenderStyle::addCallbackSelector(const String& selector) @@ -842,6 +879,25 @@ bool RenderStyle::hasIsolation() const return false; } +bool RenderStyle::hasWillChangeCompositingHint() const +{ + for (size_t i = 0; i < rareNonInheritedData->m_willChange->m_properties.size(); ++i) { + switch (rareNonInheritedData->m_willChange->m_properties[i]) { + case CSSPropertyOpacity: + case CSSPropertyTransform: + case CSSPropertyWebkitTransform: + case CSSPropertyTop: + case CSSPropertyLeft: + case CSSPropertyBottom: + case CSSPropertyRight: + return true; + default: + break; + } + } + return false; +} + inline bool requireTransformOrigin(const Vector<RefPtr<TransformOperation> >& transformOperations, RenderStyle::ApplyTransformOrigin applyOrigin) { // transform-origin brackets the transform with translate operations. @@ -878,8 +934,8 @@ void RenderStyle::applyTransform(TransformationMatrix& transform, const FloatRec float offsetY = transformOriginY().type() == Percent ? boundingBox.y() : 0; if (applyTransformOrigin) { - transform.translate3d(floatValueForLength(transformOriginX(), boundingBox.width(), 0) + offsetX, - floatValueForLength(transformOriginY(), boundingBox.height(), 0) + offsetY, + transform.translate3d(floatValueForLength(transformOriginX(), boundingBox.width()) + offsetX, + floatValueForLength(transformOriginY(), boundingBox.height()) + offsetY, transformOriginZ()); } @@ -888,8 +944,8 @@ void RenderStyle::applyTransform(TransformationMatrix& transform, const FloatRec transformOperations[i]->apply(transform, boundingBox.size()); if (applyTransformOrigin) { - transform.translate3d(-floatValueForLength(transformOriginX(), boundingBox.width(), 0) - offsetX, - -floatValueForLength(transformOriginY(), boundingBox.height(), 0) - offsetY, + transform.translate3d(-floatValueForLength(transformOriginX(), boundingBox.width()) - offsetX, + -floatValueForLength(transformOriginY(), boundingBox.height()) - offsetY, -transformOriginZ()); } } @@ -904,49 +960,17 @@ void RenderStyle::setBoxShadow(PassRefPtr<ShadowList> s) rareNonInheritedData.access()->m_boxShadow = s; } -static RoundedRect::Radii calcRadiiFor(const BorderData& border, IntSize size, RenderView* renderView) +static RoundedRect::Radii calcRadiiFor(const BorderData& border, IntSize size) { return RoundedRect::Radii( - 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) -{ - // Constrain corner radii using CSS3 rules: - // http://www.w3.org/TR/css3-background/#the-border-radius - - float factor = 1; - unsigned radiiSum; - - // top - radiiSum = static_cast<unsigned>(radii.topLeft().width()) + static_cast<unsigned>(radii.topRight().width()); // Casts to avoid integer overflow. - if (radiiSum > static_cast<unsigned>(rect.width())) - factor = min(static_cast<float>(rect.width()) / radiiSum, factor); - - // bottom - radiiSum = static_cast<unsigned>(radii.bottomLeft().width()) + static_cast<unsigned>(radii.bottomRight().width()); - if (radiiSum > static_cast<unsigned>(rect.width())) - factor = min(static_cast<float>(rect.width()) / radiiSum, factor); - - // left - radiiSum = static_cast<unsigned>(radii.topLeft().height()) + static_cast<unsigned>(radii.bottomLeft().height()); - if (radiiSum > static_cast<unsigned>(rect.height())) - factor = min(static_cast<float>(rect.height()) / radiiSum, factor); - - // right - radiiSum = static_cast<unsigned>(radii.topRight().height()) + static_cast<unsigned>(radii.bottomRight().height()); - if (radiiSum > static_cast<unsigned>(rect.height())) - factor = min(static_cast<float>(rect.height()) / radiiSum, factor); - - ASSERT(factor <= 1); - return factor; + IntSize(valueForLength(border.topLeft().width(), size.width()), + valueForLength(border.topLeft().height(), size.height())), + IntSize(valueForLength(border.topRight().width(), size.width()), + valueForLength(border.topRight().height(), size.height())), + IntSize(valueForLength(border.bottomLeft().width(), size.width()), + valueForLength(border.bottomLeft().height(), size.height())), + IntSize(valueForLength(border.bottomRight().width(), size.width()), + valueForLength(border.bottomRight().height(), size.height()))); } StyleImage* RenderStyle::listStyleImage() const { return rareInheritedData->listStyleImage.get(); } @@ -966,13 +990,13 @@ short RenderStyle::verticalBorderSpacing() const { return inherited->vertical_bo void RenderStyle::setHorizontalBorderSpacing(short v) { SET_VAR(inherited, horizontal_border_spacing, v); } void RenderStyle::setVerticalBorderSpacing(short v) { SET_VAR(inherited, vertical_border_spacing, v); } -RoundedRect RenderStyle::getRoundedBorderFor(const LayoutRect& borderRect, RenderView* renderView, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const +RoundedRect RenderStyle::getRoundedBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const { IntRect snappedBorderRect(pixelSnappedIntRect(borderRect)); RoundedRect roundedRect(snappedBorderRect); if (hasBorderRadius()) { - RoundedRect::Radii radii = calcRadiiFor(surround->border, snappedBorderRect.size(), renderView); - radii.scale(calcConstraintScaleFor(snappedBorderRect, radii)); + RoundedRect::Radii radii = calcRadiiFor(surround->border, snappedBorderRect.size()); + radii.scale(calcBorderRadiiConstraintScaleFor(borderRect, radii)); roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge); } return roundedRect; @@ -1096,111 +1120,67 @@ const AtomicString& RenderStyle::textEmphasisMarkString() const return nullAtom; } -void RenderStyle::adjustAnimations() +CSSAnimationData& RenderStyle::accessAnimations() { - CSSAnimationDataList* animationList = rareNonInheritedData->m_animations.get(); - if (!animationList) - return; - - // Get rid of empty animations and anything beyond them - for (size_t i = 0; i < animationList->size(); ++i) { - if (animationList->animation(i)->isEmpty()) { - animationList->resize(i); - break; - } - } - - if (animationList->isEmpty()) { - clearAnimations(); - return; - } - - // Repeat patterns into layers that don't have some properties set. - animationList->fillUnsetProperties(); + if (!rareNonInheritedData.access()->m_animations) + rareNonInheritedData.access()->m_animations = CSSAnimationData::create(); + return *rareNonInheritedData->m_animations; } -void RenderStyle::adjustTransitions() +CSSTransitionData& RenderStyle::accessTransitions() { - CSSAnimationDataList* transitionList = rareNonInheritedData->m_transitions.get(); - if (!transitionList) - return; + if (!rareNonInheritedData.access()->m_transitions) + rareNonInheritedData.access()->m_transitions = CSSTransitionData::create(); + return *rareNonInheritedData->m_transitions; +} - // Get rid of empty transitions and anything beyond them - for (size_t i = 0; i < transitionList->size(); ++i) { - if (transitionList->animation(i)->isEmpty()) { - transitionList->resize(i); - break; - } - } +const Font& RenderStyle::font() const { return inherited->font; } +const FontMetrics& RenderStyle::fontMetrics() const { return inherited->font.fontMetrics(); } +const FontDescription& RenderStyle::fontDescription() const { return inherited->font.fontDescription(); } +float RenderStyle::specifiedFontSize() const { return fontDescription().specifiedSize(); } +float RenderStyle::computedFontSize() const { return fontDescription().computedSize(); } +int RenderStyle::fontSize() const { return fontDescription().computedPixelSize(); } +FontWeight RenderStyle::fontWeight() const { return fontDescription().weight(); } - if (transitionList->isEmpty()) { - clearTransitions(); - return; - } +TextDecoration RenderStyle::textDecorationsInEffect() const +{ + int decorations = 0; - // Repeat patterns into layers that don't have some properties set. - transitionList->fillUnsetProperties(); - - // Make sure there are no duplicate properties. This is an O(n^2) algorithm - // but the lists tend to be very short, so it is probably ok - for (size_t i = 0; i < transitionList->size(); ++i) { - for (size_t j = i+1; j < transitionList->size(); ++j) { - if (transitionList->animation(i)->property() == transitionList->animation(j)->property()) { - // toss i - transitionList->remove(i); - j = i; - } - } - } -} + const Vector<AppliedTextDecoration>& applied = appliedTextDecorations(); -CSSAnimationDataList* RenderStyle::accessAnimations() -{ - if (!rareNonInheritedData.access()->m_animations) - rareNonInheritedData.access()->m_animations = adoptPtr(new CSSAnimationDataList()); - return rareNonInheritedData->m_animations.get(); -} + for (size_t i = 0; i < applied.size(); ++i) + decorations |= applied[i].line(); -CSSAnimationDataList* RenderStyle::accessTransitions() -{ - if (!rareNonInheritedData.access()->m_transitions) - rareNonInheritedData.access()->m_transitions = adoptPtr(new CSSAnimationDataList()); - return rareNonInheritedData->m_transitions.get(); + return static_cast<TextDecoration>(decorations); } -const CSSAnimationData* RenderStyle::transitionForProperty(CSSPropertyID property) const +const Vector<AppliedTextDecoration>& RenderStyle::appliedTextDecorations() const { - if (transitions()) { - for (size_t i = 0; i < transitions()->size(); ++i) { - const CSSAnimationData* p = transitions()->animation(i); - if (p->animationMode() == CSSAnimationData::AnimateAll || p->property() == property) { - return p; - } - } + if (!inherited_flags.m_textUnderline && !rareInheritedData->appliedTextDecorations) { + DEFINE_STATIC_LOCAL(Vector<AppliedTextDecoration>, empty, ()); + return empty; + } + if (inherited_flags.m_textUnderline) { + DEFINE_STATIC_LOCAL(Vector<AppliedTextDecoration>, underline, (1, AppliedTextDecoration(TextDecorationUnderline))); + return underline; } - return 0; -} -const Font& RenderStyle::font() const { return inherited->font; } -const FontMetrics& RenderStyle::fontMetrics() const { return inherited->font.fontMetrics(); } -const FontDescription& RenderStyle::fontDescription() const { return inherited->font.fontDescription(); } -float RenderStyle::specifiedFontSize() const { return fontDescription().specifiedSize(); } -float RenderStyle::computedFontSize() const { return fontDescription().computedSize(); } -int RenderStyle::fontSize() const { return inherited->font.pixelSize(); } + return rareInheritedData->appliedTextDecorations->vector(); +} -float RenderStyle::wordSpacing() const { return inherited->font.wordSpacing(); } -float RenderStyle::letterSpacing() const { return inherited->font.letterSpacing(); } +float RenderStyle::wordSpacing() const { return fontDescription().wordSpacing(); } +float RenderStyle::letterSpacing() const { return fontDescription().letterSpacing(); } bool RenderStyle::setFontDescription(const FontDescription& v) { if (inherited->font.fontDescription() != v) { - inherited.access()->font = Font(v, inherited->font.letterSpacing(), inherited->font.wordSpacing()); + inherited.access()->font = Font(v); return true; } return false; } -Length RenderStyle::specifiedLineHeight() const { return inherited->line_height; } +const Length& RenderStyle::specifiedLineHeight() const { return inherited->line_height; } Length RenderStyle::lineHeight() const { const Length& lh = inherited->line_height; @@ -1214,9 +1194,10 @@ Length RenderStyle::lineHeight() const return lh; } -void RenderStyle::setLineHeight(Length specifiedLineHeight) { SET_VAR(inherited, line_height, specifiedLineHeight); } -int RenderStyle::computedLineHeight(RenderView* renderView) const +void RenderStyle::setLineHeight(const Length& specifiedLineHeight) { SET_VAR(inherited, line_height, specifiedLineHeight); } + +int RenderStyle::computedLineHeight() const { const Length& lh = lineHeight(); @@ -1227,14 +1208,26 @@ int RenderStyle::computedLineHeight(RenderView* renderView) const if (lh.isPercent()) return minimumValueForLength(lh, fontSize()); - if (lh.isViewportPercentage()) - return valueForLength(lh, 0, renderView); - return lh.value(); } -void RenderStyle::setWordSpacing(float v) { inherited.access()->font.setWordSpacing(v); } -void RenderStyle::setLetterSpacing(float v) { inherited.access()->font.setLetterSpacing(v); } +void RenderStyle::setWordSpacing(float wordSpacing) +{ + FontSelector* currentFontSelector = font().fontSelector(); + FontDescription desc(fontDescription()); + desc.setWordSpacing(wordSpacing); + setFontDescription(desc); + font().update(currentFontSelector); +} + +void RenderStyle::setLetterSpacing(float letterSpacing) +{ + FontSelector* currentFontSelector = font().fontSelector(); + FontDescription desc(fontDescription()); + desc.setLetterSpacing(letterSpacing); + setFontDescription(desc); + font().update(currentFontSelector); +} void RenderStyle::setFontSize(float size) { @@ -1262,6 +1255,66 @@ void RenderStyle::setFontSize(float size) font().update(currentFontSelector); } +void RenderStyle::setFontWeight(FontWeight weight) +{ + FontSelector* currentFontSelector = font().fontSelector(); + FontDescription desc(fontDescription()); + desc.setWeight(weight); + setFontDescription(desc); + font().update(currentFontSelector); +} + +void RenderStyle::addAppliedTextDecoration(const AppliedTextDecoration& decoration) +{ + RefPtr<AppliedTextDecorationList>& list = rareInheritedData.access()->appliedTextDecorations; + + if (!list) + list = AppliedTextDecorationList::create(); + else if (!list->hasOneRef()) + list = list->copy(); + + if (inherited_flags.m_textUnderline) { + inherited_flags.m_textUnderline = false; + list->append(AppliedTextDecoration(TextDecorationUnderline)); + } + + list->append(decoration); +} + +void RenderStyle::applyTextDecorations() +{ + if (textDecoration() == TextDecorationNone) + return; + + TextDecorationStyle style = textDecorationStyle(); + StyleColor styleColor = visitedDependentDecorationStyleColor(); + + int decorations = textDecoration(); + + if (decorations & TextDecorationUnderline) { + // To save memory, we don't use AppliedTextDecoration objects in the + // common case of a single simple underline. + AppliedTextDecoration underline(TextDecorationUnderline, style, styleColor); + + if (!rareInheritedData->appliedTextDecorations && underline.isSimpleUnderline()) + inherited_flags.m_textUnderline = true; + else + addAppliedTextDecoration(underline); + } + if (decorations & TextDecorationOverline) + addAppliedTextDecoration(AppliedTextDecoration(TextDecorationOverline, style, styleColor)); + if (decorations & TextDecorationLineThrough) + addAppliedTextDecoration(AppliedTextDecoration(TextDecorationLineThrough, style, styleColor)); +} + +void RenderStyle::clearAppliedTextDecorations() +{ + inherited_flags.m_textUnderline = false; + + if (rareInheritedData->appliedTextDecorations) + rareInheritedData.access()->appliedTextDecorations = nullptr; +} + void RenderStyle::getShadowExtent(const ShadowList* shadowList, LayoutUnit &top, LayoutUnit &right, LayoutUnit &bottom, LayoutUnit &left) const { top = 0; @@ -1274,7 +1327,7 @@ void RenderStyle::getShadowExtent(const ShadowList* shadowList, LayoutUnit &top, const ShadowData& shadow = shadowList->shadows()[i]; if (shadow.style() == Inset) continue; - int blurAndSpread = shadow.blur() + shadow.spread(); + float blurAndSpread = shadow.blur() + shadow.spread(); top = min<LayoutUnit>(top, shadow.y() - blurAndSpread); right = max<LayoutUnit>(right, shadow.x() + blurAndSpread); @@ -1295,7 +1348,7 @@ LayoutBoxExtent RenderStyle::getShadowInsetExtent(const ShadowList* shadowList) const ShadowData& shadow = shadowList->shadows()[i]; if (shadow.style() == Normal) continue; - int blurAndSpread = shadow.blur() + shadow.spread(); + float blurAndSpread = shadow.blur() + shadow.spread(); top = max<LayoutUnit>(top, shadow.y() + blurAndSpread); right = min<LayoutUnit>(right, shadow.x() - blurAndSpread); bottom = min<LayoutUnit>(bottom, shadow.y() - blurAndSpread); @@ -1315,7 +1368,7 @@ void RenderStyle::getShadowHorizontalExtent(const ShadowList* shadowList, Layout const ShadowData& shadow = shadowList->shadows()[i]; if (shadow.style() == Inset) continue; - int blurAndSpread = shadow.blur() + shadow.spread(); + float blurAndSpread = shadow.blur() + shadow.spread(); left = min<LayoutUnit>(left, shadow.x() - blurAndSpread); right = max<LayoutUnit>(right, shadow.x() + blurAndSpread); @@ -1332,20 +1385,46 @@ void RenderStyle::getShadowVerticalExtent(const ShadowList* shadowList, LayoutUn const ShadowData& shadow = shadowList->shadows()[i]; if (shadow.style() == Inset) continue; - int blurAndSpread = shadow.blur() + shadow.spread(); + float blurAndSpread = shadow.blur() + shadow.spread(); top = min<LayoutUnit>(top, shadow.y() - blurAndSpread); bottom = max<LayoutUnit>(bottom, shadow.y() + blurAndSpread); } } +StyleColor RenderStyle::visitedDependentDecorationStyleColor() const +{ + bool isVisited = insideLink() == InsideVisitedLink; + + StyleColor styleColor = isVisited ? visitedLinkTextDecorationColor() : textDecorationColor(); + + if (!styleColor.isCurrentColor()) + return styleColor; + + if (textStrokeWidth()) { + // Prefer stroke color if possible, but not if it's fully transparent. + StyleColor textStrokeStyleColor = isVisited ? visitedLinkTextStrokeColor() : textStrokeColor(); + if (!textStrokeStyleColor.isCurrentColor() && textStrokeStyleColor.color().alpha()) + return textStrokeStyleColor; + } + + return isVisited ? visitedLinkTextFillColor() : textFillColor(); +} + +Color RenderStyle::visitedDependentDecorationColor() const +{ + bool isVisited = insideLink() == InsideVisitedLink; + return visitedDependentDecorationStyleColor().resolve(isVisited ? visitedLinkColor() : color()); +} + Color RenderStyle::colorIncludingFallback(int colorProperty, bool visitedLink) const { - Color result; + StyleColor result(StyleColor::currentColor()); EBorderStyle borderStyle = BNONE; switch (colorProperty) { case CSSPropertyBackgroundColor: - return visitedLink ? visitedLinkBackgroundColor() : backgroundColor(); // Background color doesn't fall back. + result = visitedLink ? visitedLinkBackgroundColor() : backgroundColor(); + break; case CSSPropertyBorderLeftColor: result = visitedLink ? visitedLinkBorderLeftColor() : borderLeftColor(); borderStyle = borderLeftStyle(); @@ -1371,9 +1450,6 @@ Color RenderStyle::colorIncludingFallback(int colorProperty, bool visitedLink) c case CSSPropertyWebkitColumnRuleColor: result = visitedLink ? visitedLinkColumnRuleColor() : columnRuleColor(); break; - case CSSPropertyTextDecorationColor: - // Text decoration color fallback is handled in RenderObject::decorationColor. - return visitedLink ? visitedLinkTextDecorationColor() : textDecorationColor(); case CSSPropertyWebkitTextEmphasisColor: result = visitedLink ? visitedLinkTextEmphasisColor() : textEmphasisColor(); break; @@ -1400,13 +1476,14 @@ Color RenderStyle::colorIncludingFallback(int colorProperty, bool visitedLink) c break; } - if (!result.isValid()) { - if (!visitedLink && (borderStyle == INSET || borderStyle == OUTSET || borderStyle == RIDGE || borderStyle == GROOVE)) - result.setRGB(238, 238, 238); - else - result = visitedLink ? visitedLinkColor() : color(); - } - return result; + if (!result.isCurrentColor()) + return result.color(); + + // FIXME: Treating styled borders with initial color differently causes problems + // See crbug.com/316559, crbug.com/276231 + if (!visitedLink && (borderStyle == INSET || borderStyle == OUTSET || borderStyle == RIDGE || borderStyle == GROOVE)) + return Color(238, 238, 238); + return visitedLink ? visitedLinkColor() : color(); } Color RenderStyle::visitedDependentColor(int colorProperty) const @@ -1417,10 +1494,6 @@ Color RenderStyle::visitedDependentColor(int colorProperty) const Color visitedColor = colorIncludingFallback(colorProperty, true); - // Text decoration color validity is preserved (checked in RenderObject::decorationColor). - if (colorProperty == CSSPropertyTextDecorationColor) - return visitedColor; - // FIXME: Technically someone could explicitly specify the color transparent, but for now we'll just // assume that if the background color is transparent that it wasn't set. Note that it's weird that // we're returning unvisited info for a visited link, but given our restriction that the alpha values @@ -1525,7 +1598,7 @@ unsigned short RenderStyle::borderEndWidth() const return isLeftToRightDirection() ? borderBottomWidth() : borderTopWidth(); } -void RenderStyle::setMarginStart(Length margin) +void RenderStyle::setMarginStart(const Length& margin) { if (isHorizontalWritingMode()) { if (isLeftToRightDirection()) @@ -1540,7 +1613,7 @@ void RenderStyle::setMarginStart(Length margin) } } -void RenderStyle::setMarginEnd(Length margin) +void RenderStyle::setMarginEnd(const Length& margin) { if (isHorizontalWritingMode()) { if (isLeftToRightDirection()) @@ -1587,7 +1660,7 @@ void RenderStyle::setBorderImageSource(PassRefPtr<StyleImage> image) surround.access()->border.m_image.setImage(image); } -void RenderStyle::setBorderImageSlices(LengthBox slices) +void RenderStyle::setBorderImageSlices(const LengthBox& slices) { if (surround->border.m_image.imageSlices() == slices) return; @@ -1608,4 +1681,36 @@ void RenderStyle::setBorderImageOutset(const BorderImageLengthBox& outset) surround.access()->border.m_image.setOutset(outset); } +float calcBorderRadiiConstraintScaleFor(const FloatRect& rect, const FloatRoundedRect::Radii& radii) +{ + // Constrain corner radii using CSS3 rules: + // http://www.w3.org/TR/css3-background/#the-border-radius + + float factor = 1; + float radiiSum; + + // top + radiiSum = radii.topLeft().width() + radii.topRight().width(); // Casts to avoid integer overflow. + if (radiiSum > rect.width()) + factor = std::min(rect.width() / radiiSum, factor); + + // bottom + radiiSum = radii.bottomLeft().width() + radii.bottomRight().width(); + if (radiiSum > rect.width()) + factor = std::min(rect.width() / radiiSum, factor); + + // left + radiiSum = radii.topLeft().height() + radii.bottomLeft().height(); + if (radiiSum > rect.height()) + factor = std::min(rect.height() / radiiSum, factor); + + // right + radiiSum = radii.topRight().height() + radii.bottomRight().height(); + if (radiiSum > rect.height()) + factor = std::min(rect.height() / radiiSum, factor); + + ASSERT(factor <= 1); + return factor; +} + } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/RenderStyle.h b/chromium/third_party/WebKit/Source/core/rendering/style/RenderStyle.h index f405b951fbe..543c815d06d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/RenderStyle.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/RenderStyle.h @@ -25,11 +25,11 @@ #ifndef RenderStyle_h #define RenderStyle_h -#include "CSSPropertyNames.h" -#include "core/css/CSSLengthFunctions.h" +#include "core/CSSPropertyNames.h" +#include "core/animation/css/CSSAnimationData.h" +#include "core/animation/css/CSSTransitionData.h" #include "core/css/CSSLineBoxContainValue.h" #include "core/css/CSSPrimitiveValue.h" -#include "core/platform/animation/CSSAnimationDataList.h" #include "core/rendering/style/BorderValue.h" #include "core/rendering/style/CounterDirectives.h" #include "core/rendering/style/DataRef.h" @@ -42,10 +42,12 @@ #include "core/rendering/style/StyleBackgroundData.h" #include "core/rendering/style/StyleBoxData.h" #include "core/rendering/style/StyleDeprecatedFlexibleBoxData.h" +#include "core/rendering/style/StyleDifference.h" #include "core/rendering/style/StyleFilterData.h" #include "core/rendering/style/StyleFlexibleBoxData.h" #include "core/rendering/style/StyleGridData.h" #include "core/rendering/style/StyleGridItemData.h" +#include "core/rendering/style/StyleInheritedData.h" #include "core/rendering/style/StyleMarqueeData.h" #include "core/rendering/style/StyleMultiColData.h" #include "core/rendering/style/StyleRareInheritedData.h" @@ -54,6 +56,7 @@ #include "core/rendering/style/StyleSurroundData.h" #include "core/rendering/style/StyleTransformData.h" #include "core/rendering/style/StyleVisualData.h" +#include "core/rendering/style/StyleWillChangeData.h" #include "core/svg/SVGPaint.h" #include "platform/Length.h" #include "platform/LengthBox.h" @@ -61,10 +64,12 @@ #include "platform/ThemeTypes.h" #include "platform/fonts/FontBaseline.h" #include "platform/fonts/FontDescription.h" +#include "platform/geometry/FloatRoundedRect.h" #include "platform/geometry/LayoutBoxExtent.h" #include "platform/geometry/RoundedRect.h" #include "platform/graphics/Color.h" #include "platform/graphics/GraphicsTypes.h" +#include "platform/scroll/ScrollableArea.h" #include "platform/text/TextDirection.h" #include "platform/text/UnicodeBidi.h" #include "platform/transforms/TransformOperations.h" @@ -80,6 +85,10 @@ 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_VAR_WITH_SETTER(group, getter, setter, value) \ + if (!compareEqual(group->getter(), value)) \ + group.access()->setter(value) + #define SET_BORDERVALUE_COLOR(group, variable, value) \ if (!compareEqual(group->variable.color(), value)) \ group.access()->variable.setColor(value) @@ -90,13 +99,11 @@ using std::max; class FilterOperations; +class AppliedTextDecoration; class BorderData; class CounterContent; -class CursorList; class Font; class FontMetrics; -class IntRect; -class Pair; class ShadowList; class StyleImage; class StyleInheritedData; @@ -110,11 +117,11 @@ typedef Vector<RefPtr<RenderStyle>, 4> PseudoStyleCache; class RenderStyle: public RefCounted<RenderStyle> { friend class AnimatedStyleBuilder; // Used by Web Animations CSS. Sets the color styles friend class CSSAnimatableValueFactory; // Used by Web Animations CSS. Gets visited and unvisited colors separately. - friend class CSSPropertyAnimation; // Used by CSS animations. We can't allow them to animate based off visited colors. + friend class CSSPropertyEquality; // 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 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 PropertyWrapperMaybeInvalidStyleColor; // Used by CSS animations. We can't allow them to animate based off visited colors. friend class StyleBuilderFunctions; // Sets color styles friend class CachedUAStyle; // Saves Border/Background information for later comparison. @@ -156,7 +163,7 @@ protected: && (_visibility == other._visibility) && (_text_align == other._text_align) && (_text_transform == other._text_transform) - && (_text_decorations == other._text_decorations) + && (m_textUnderline == other.m_textUnderline) && (_cursor_style == other._cursor_style) && (_direction == other._direction) && (_white_space == other._white_space) @@ -178,24 +185,23 @@ protected: unsigned _visibility : 2; // EVisibility unsigned _text_align : 4; // ETextAlign unsigned _text_transform : 2; // ETextTransform - unsigned _text_decorations : TextDecorationBits; + unsigned m_textUnderline : 1; unsigned _cursor_style : 6; // ECursor unsigned _direction : 1; // TextDirection unsigned _white_space : 3; // EWhiteSpace - // 32 bits unsigned _border_collapse : 1; // EBorderCollapse unsigned _box_direction : 1; // EBoxDirection (CSS3 box_direction property, flexible box layout module) + // 32 bits // non CSS2 inherited unsigned m_rtlOrdering : 1; // Order unsigned m_printColorAdjust : PrintColorAdjustBits; unsigned _pointerEvents : 4; // EPointerEvents unsigned _insideLink : 2; // EInsideLink - // 43 bits // CSS Text Layout Module Level 3: Vertical writing support unsigned m_writingMode : 2; // WritingMode - // 45 bits + // 42 bits } inherited_flags; // don't inherit @@ -243,7 +249,13 @@ protected: unsigned _table_layout : 1; // ETableLayout unsigned _unicodeBidi : 3; // EUnicodeBidi - // 31 bits + + // This is set if we used viewport units when resolving a length. + // It is mutable so we can pass around const RenderStyles to resolve lengths. + mutable unsigned hasViewportUnits : 1; + + // 32 bits + unsigned _page_break_before : 2; // EPageBreak unsigned _page_break_after : 2; // EPageBreak unsigned _page_break_inside : 2; // EPageBreak @@ -274,7 +286,7 @@ protected: unsigned _affectedByDrag : 1; unsigned _isLink : 1; // If you add more style bits here, you will also need to update RenderStyle::copyNonInheritedFrom() - // 60 bits + // 63 bits } noninherited_flags; // !END SYNC! @@ -289,7 +301,7 @@ protected: inherited_flags._visibility = initialVisibility(); inherited_flags._text_align = initialTextAlign(); inherited_flags._text_transform = initialTextTransform(); - inherited_flags._text_decorations = initialTextDecoration(); + inherited_flags.m_textUnderline = false; inherited_flags._cursor_style = initialCursor(); inherited_flags._direction = initialDirection(); inherited_flags._white_space = initialWhiteSpace(); @@ -321,6 +333,7 @@ protected: noninherited_flags.emptyState = false; noninherited_flags.firstChildState = false; noninherited_flags.lastChildState = false; + noninherited_flags.hasViewportUnits = false; noninherited_flags.setAffectedByFocus(false); noninherited_flags.setAffectedByHover(false); noninherited_flags.setAffectedByActive(false); @@ -343,7 +356,11 @@ public: static PassRefPtr<RenderStyle> createAnonymousStyleWithDisplay(const RenderStyle* parentStyle, EDisplay); static PassRefPtr<RenderStyle> clone(const RenderStyle*); - static StyleRecalcChange compare(const RenderStyle* oldStyle, const RenderStyle* newStyle); + // Computes how the style change should be propagated down the tree. + static StyleRecalcChange stylePropagationDiff(const RenderStyle* oldStyle, const RenderStyle* newStyle); + + // Computes how much visual invalidation the style change causes: layout, repaint or recomposite. + StyleDifference visualInvalidationDiff(const RenderStyle&, unsigned& changedContextSensitiveProperties) const; enum IsAtShadowBoundary { AtShadowBoundary, @@ -362,8 +379,8 @@ public: const PseudoStyleCache* cachedPseudoStyles() const { return m_cachedPseudoStyles.get(); } - void setVariable(const AtomicString& name, const String& value) { rareInheritedData.access()->m_variables.access()->setVariable(name, value); } - const HashMap<AtomicString, String>* variables() { return &(rareInheritedData->m_variables->m_data); } + void setHasViewportUnits(bool hasViewportUnits = true) const { noninherited_flags.hasViewportUnits = hasViewportUnits; } + bool hasViewportUnits() const { return noninherited_flags.hasViewportUnits; } bool affectedByFocus() const { return noninherited_flags.affectedByFocus(); } bool affectedByHover() const { return noninherited_flags.affectedByHover(); } @@ -395,7 +412,7 @@ public: bool hasBackground() const { Color color = visitedDependentColor(CSSPropertyBackgroundColor); - if (color.isValid() && color.alpha()) + if (color.alpha()) return true; return hasBackgroundImage(); } @@ -427,22 +444,23 @@ public: bool hasPseudoStyle(PseudoId pseudo) const; void setHasPseudoStyle(PseudoId pseudo); bool hasUniquePseudoStyle() const; + bool hasPseudoElementStyle() const; // attribute getter methods EDisplay display() const { return static_cast<EDisplay>(noninherited_flags._effectiveDisplay); } EDisplay originalDisplay() const { return static_cast<EDisplay>(noninherited_flags._originalDisplay); } - Length left() const { return surround->offset.left(); } - Length right() const { return surround->offset.right(); } - Length top() const { return surround->offset.top(); } - Length bottom() const { return surround->offset.bottom(); } + const Length& left() const { return surround->offset.left(); } + const Length& right() const { return surround->offset.right(); } + const Length& top() const { return surround->offset.top(); } + const Length& bottom() const { return surround->offset.bottom(); } // Accessors for positioned object edges that take into account writing mode. - Length logicalLeft() const { return surround->offset.logicalLeft(writingMode()); } - Length logicalRight() const { return surround->offset.logicalRight(writingMode()); } - Length logicalTop() const { return surround->offset.before(writingMode()); } - Length logicalBottom() const { return surround->offset.after(writingMode()); } + const Length& logicalLeft() const { return surround->offset.logicalLeft(writingMode()); } + const Length& logicalRight() const { return surround->offset.logicalRight(writingMode()); } + const Length& logicalTop() const { return surround->offset.before(writingMode()); } + const Length& logicalBottom() const { return surround->offset.after(writingMode()); } // Whether or not a positioned element requires normal flow x/y to be computed // to determine its position. @@ -457,19 +475,19 @@ public: bool hasViewportConstrainedPosition() const { return position() == FixedPosition || position() == StickyPosition; } EFloat floating() const { return static_cast<EFloat>(noninherited_flags._floating); } - Length width() const { return m_box->width(); } - Length height() const { return m_box->height(); } - Length minWidth() const { return m_box->minWidth(); } - Length maxWidth() const { return m_box->maxWidth(); } - Length minHeight() const { return m_box->minHeight(); } - Length maxHeight() const { return m_box->maxHeight(); } + const Length& width() const { return m_box->width(); } + const Length& height() const { return m_box->height(); } + const Length& minWidth() const { return m_box->minWidth(); } + const Length& maxWidth() const { return m_box->maxWidth(); } + const Length& minHeight() const { return m_box->minHeight(); } + const Length& maxHeight() const { return m_box->maxHeight(); } - Length logicalWidth() const { return isHorizontalWritingMode() ? width() : height(); } - Length logicalHeight() const { return isHorizontalWritingMode() ? height() : width(); } - Length logicalMinWidth() const { return isHorizontalWritingMode() ? minWidth() : minHeight(); } - Length logicalMaxWidth() const { return isHorizontalWritingMode() ? maxWidth() : maxHeight(); } - Length logicalMinHeight() const { return isHorizontalWritingMode() ? minHeight() : minWidth(); } - Length logicalMaxHeight() const { return isHorizontalWritingMode() ? maxHeight() : maxWidth(); } + const Length& logicalWidth() const { return isHorizontalWritingMode() ? width() : height(); } + const Length& logicalHeight() const { return isHorizontalWritingMode() ? height() : width(); } + const Length& logicalMinWidth() const { return isHorizontalWritingMode() ? minWidth() : minHeight(); } + const Length& logicalMaxWidth() const { return isHorizontalWritingMode() ? maxWidth() : maxHeight(); } + const Length& logicalMinHeight() const { return isHorizontalWritingMode() ? minHeight() : minWidth(); } + const Length& logicalMaxHeight() const { return isHorizontalWritingMode() ? maxHeight() : maxWidth(); } const BorderData& border() const { return surround->border; } const BorderValue& borderLeft() const { return surround->border.left(); } @@ -484,14 +502,14 @@ public: const NinePieceImage& borderImage() const { return surround->border.image(); } StyleImage* borderImageSource() const { return surround->border.image().image(); } - LengthBox borderImageSlices() const { return surround->border.image().imageSlices(); } + const LengthBox& borderImageSlices() const { return surround->border.image().imageSlices(); } const BorderImageLengthBox& borderImageWidth() const { return surround->border.image().borderSlices(); } const BorderImageLengthBox& borderImageOutset() const { return surround->border.image().outset(); } - LengthSize borderTopLeftRadius() const { return surround->border.topLeft(); } - LengthSize borderTopRightRadius() const { return surround->border.topRight(); } - LengthSize borderBottomLeftRadius() const { return surround->border.bottomLeft(); } - LengthSize borderBottomRightRadius() const { return surround->border.bottomRight(); } + const LengthSize& borderTopLeftRadius() const { return surround->border.topLeft(); } + const LengthSize& borderTopRightRadius() const { return surround->border.topRight(); } + const LengthSize& borderBottomLeftRadius() const { return surround->border.bottomLeft(); } + const LengthSize& borderBottomRightRadius() const { return surround->border.bottomRight(); } bool hasBorderRadius() const { return surround->border.hasBorderRadius(); } unsigned borderLeftWidth() const { return surround->border.borderLeftWidth(); } @@ -525,22 +543,26 @@ public: EOverflow overflowX() const { return static_cast<EOverflow>(noninherited_flags._overflowX); } EOverflow overflowY() const { return static_cast<EOverflow>(noninherited_flags._overflowY); } + // It's sufficient to just check one direction, since it's illegal to have visible on only one overflow value. + bool isOverflowVisible() const { ASSERT(overflowX() != OVISIBLE || overflowX() == overflowY()); return overflowX() == OVISIBLE; } + bool isOverflowPaged() const { return overflowY() == OPAGEDX || overflowY() == OPAGEDY; } EVisibility visibility() const { return static_cast<EVisibility>(inherited_flags._visibility); } EVerticalAlign verticalAlign() const { return static_cast<EVerticalAlign>(noninherited_flags._vertical_align); } - Length verticalAlignLength() const { return m_box->verticalAlign(); } + const Length& verticalAlignLength() const { return m_box->verticalAlign(); } - Length clipLeft() const { return visual->clip.left(); } - Length clipRight() const { return visual->clip.right(); } - Length clipTop() const { return visual->clip.top(); } - Length clipBottom() const { return visual->clip.bottom(); } - LengthBox clip() const { return visual->clip; } + const Length& clipLeft() const { return visual->clip.left(); } + const Length& clipRight() const { return visual->clip.right(); } + const Length& clipTop() const { return visual->clip.top(); } + const Length& clipBottom() const { return visual->clip.bottom(); } + const LengthBox& clip() const { return visual->clip; } bool hasClip() const { return visual->hasClip; } EUnicodeBidi unicodeBidi() const { return static_cast<EUnicodeBidi>(noninherited_flags._unicodeBidi); } EClear clear() const { return static_cast<EClear>(noninherited_flags._clear); } ETableLayout tableLayout() const { return static_cast<ETableLayout>(noninherited_flags._table_layout); } + bool isFixedTableLayout() const { return tableLayout() == TFIXED && !logicalWidth().isAuto(); } const Font& font() const; const FontMetrics& fontMetrics() const; @@ -548,16 +570,19 @@ public: float specifiedFontSize() const; float computedFontSize() const; int fontSize() const; + FontWeight fontWeight() const; - float textAutosizingMultiplier() const { return visual->m_textAutosizingMultiplier; } + float textAutosizingMultiplier() const { return inherited->textAutosizingMultiplier; } - Length textIndent() const { return rareInheritedData->indent; } + const Length& textIndent() const { return rareInheritedData->indent; } TextIndentLine textIndentLine() const { return static_cast<TextIndentLine>(rareInheritedData->m_textIndentLine); } + TextIndentType textIndentType() const { return static_cast<TextIndentType>(rareInheritedData->m_textIndentType); } ETextAlign textAlign() const { return static_cast<ETextAlign>(inherited_flags._text_align); } TextAlignLast textAlignLast() const { return static_cast<TextAlignLast>(rareInheritedData->m_textAlignLast); } TextJustify textJustify() const { return static_cast<TextJustify>(rareInheritedData->m_textJustify); } ETextTransform textTransform() const { return static_cast<ETextTransform>(inherited_flags._text_transform); } - TextDecoration textDecorationsInEffect() const { return static_cast<TextDecoration>(inherited_flags._text_decorations); } + TextDecoration textDecorationsInEffect() const; + const Vector<AppliedTextDecoration>& appliedTextDecorations() const; TextDecoration textDecoration() const { return static_cast<TextDecoration>(visual->textDecoration); } TextUnderlinePosition textUnderlinePosition() const { return static_cast<TextUnderlinePosition>(rareInheritedData->m_textUnderlinePosition); } TextDecorationStyle textDecorationStyle() const { return static_cast<TextDecorationStyle>(rareNonInheritedData->m_textDecorationStyle); } @@ -570,9 +595,9 @@ public: TextDirection direction() const { return static_cast<TextDirection>(inherited_flags._direction); } bool isLeftToRightDirection() const { return direction() == LTR; } - Length specifiedLineHeight() const; + const Length& specifiedLineHeight() const; Length lineHeight() const; - int computedLineHeight(RenderView* = 0) const; + int computedLineHeight() const; EWhiteSpace whiteSpace() const { return static_cast<EWhiteSpace>(inherited_flags._white_space); } static bool autoWrap(EWhiteSpace ws) @@ -636,10 +661,10 @@ public: EFillAttachment backgroundAttachment() const { return static_cast<EFillAttachment>(m_background->background().attachment()); } EFillBox backgroundClip() const { return static_cast<EFillBox>(m_background->background().clip()); } EFillBox backgroundOrigin() const { return static_cast<EFillBox>(m_background->background().origin()); } - Length backgroundXPosition() const { return m_background->background().xPosition(); } - Length backgroundYPosition() const { return m_background->background().yPosition(); } + const Length& backgroundXPosition() const { return m_background->background().xPosition(); } + const Length& backgroundYPosition() const { return m_background->background().yPosition(); } EFillSizeType backgroundSizeType() const { return m_background->background().sizeType(); } - LengthSize backgroundSizeLength() const { return m_background->background().sizeLength(); } + const LengthSize& backgroundSizeLength() const { return m_background->background().sizeLength(); } FillLayer* accessBackgroundLayers() { return &(m_background.access()->m_background); } const FillLayer* backgroundLayers() const { return &(m_background->background()); } @@ -649,16 +674,16 @@ public: CompositeOperator maskComposite() const { return static_cast<CompositeOperator>(rareNonInheritedData->m_mask.composite()); } EFillBox maskClip() const { return static_cast<EFillBox>(rareNonInheritedData->m_mask.clip()); } EFillBox maskOrigin() const { return static_cast<EFillBox>(rareNonInheritedData->m_mask.origin()); } - Length maskXPosition() const { return rareNonInheritedData->m_mask.xPosition(); } - Length maskYPosition() const { return rareNonInheritedData->m_mask.yPosition(); } + const Length& maskXPosition() const { return rareNonInheritedData->m_mask.xPosition(); } + const Length& maskYPosition() const { return rareNonInheritedData->m_mask.yPosition(); } EFillSizeType maskSizeType() const { return rareNonInheritedData->m_mask.sizeType(); } - LengthSize maskSizeLength() const { return rareNonInheritedData->m_mask.sizeLength(); } + const LengthSize& maskSizeLength() const { return rareNonInheritedData->m_mask.sizeLength(); } FillLayer* accessMaskLayers() { return &(rareNonInheritedData.access()->m_mask); } const FillLayer* maskLayers() const { return &(rareNonInheritedData->m_mask); } const NinePieceImage& maskBoxImage() const { return rareNonInheritedData->m_maskBoxImage; } StyleImage* maskBoxImageSource() const { return rareNonInheritedData->m_maskBoxImage.image(); } - LengthBox maskBoxImageSlices() const { return rareNonInheritedData->m_maskBoxImage.imageSlices(); } + const LengthBox& maskBoxImageSlices() const { return rareNonInheritedData->m_maskBoxImage.imageSlices(); } bool maskBoxImageSlicesFill() const { return rareNonInheritedData->m_maskBoxImage.fill(); } const BorderImageLengthBox& maskBoxImageWidth() const { return rareNonInheritedData->m_maskBoxImage.borderSlices(); } const BorderImageLengthBox& maskBoxImageOutset() const { return rareNonInheritedData->m_maskBoxImage.outset(); } @@ -673,28 +698,28 @@ public: StyleImage* listStyleImage() const; EListStylePosition listStylePosition() const { return static_cast<EListStylePosition>(inherited_flags._list_style_position); } - Length marginTop() const { return surround->margin.top(); } - Length marginBottom() const { return surround->margin.bottom(); } - Length marginLeft() const { return surround->margin.left(); } - Length marginRight() const { return surround->margin.right(); } - Length marginBefore() const { return surround->margin.before(writingMode()); } - Length marginAfter() const { return surround->margin.after(writingMode()); } - Length marginStart() const { return surround->margin.start(writingMode(), direction()); } - Length marginEnd() const { return surround->margin.end(writingMode(), direction()); } - Length marginStartUsing(const RenderStyle* otherStyle) const { return surround->margin.start(otherStyle->writingMode(), otherStyle->direction()); } - Length marginEndUsing(const RenderStyle* otherStyle) const { return surround->margin.end(otherStyle->writingMode(), otherStyle->direction()); } - Length marginBeforeUsing(const RenderStyle* otherStyle) const { return surround->margin.before(otherStyle->writingMode()); } - Length marginAfterUsing(const RenderStyle* otherStyle) const { return surround->margin.after(otherStyle->writingMode()); } - - LengthBox paddingBox() const { return surround->padding; } - Length paddingTop() const { return surround->padding.top(); } - Length paddingBottom() const { return surround->padding.bottom(); } - Length paddingLeft() const { return surround->padding.left(); } - Length paddingRight() const { return surround->padding.right(); } - Length paddingBefore() const { return surround->padding.before(writingMode()); } - Length paddingAfter() const { return surround->padding.after(writingMode()); } - Length paddingStart() const { return surround->padding.start(writingMode(), direction()); } - Length paddingEnd() const { return surround->padding.end(writingMode(), direction()); } + const Length& marginTop() const { return surround->margin.top(); } + const Length& marginBottom() const { return surround->margin.bottom(); } + const Length& marginLeft() const { return surround->margin.left(); } + const Length& marginRight() const { return surround->margin.right(); } + const Length& marginBefore() const { return surround->margin.before(writingMode()); } + const Length& marginAfter() const { return surround->margin.after(writingMode()); } + const Length& marginStart() const { return surround->margin.start(writingMode(), direction()); } + const Length& marginEnd() const { return surround->margin.end(writingMode(), direction()); } + const Length& marginStartUsing(const RenderStyle* otherStyle) const { return surround->margin.start(otherStyle->writingMode(), otherStyle->direction()); } + const Length& marginEndUsing(const RenderStyle* otherStyle) const { return surround->margin.end(otherStyle->writingMode(), otherStyle->direction()); } + const Length& marginBeforeUsing(const RenderStyle* otherStyle) const { return surround->margin.before(otherStyle->writingMode()); } + const Length& marginAfterUsing(const RenderStyle* otherStyle) const { return surround->margin.after(otherStyle->writingMode()); } + + const LengthBox& paddingBox() const { return surround->padding; } + const Length& paddingTop() const { return surround->padding.top(); } + const Length& paddingBottom() const { return surround->padding.bottom(); } + const Length& paddingLeft() const { return surround->padding.left(); } + const Length& paddingRight() const { return surround->padding.right(); } + const Length& paddingBefore() const { return surround->padding.before(writingMode()); } + const Length& paddingAfter() const { return surround->padding.after(writingMode()); } + const Length& paddingStart() const { return surround->padding.start(writingMode(), direction()); } + const Length& paddingEnd() const { return surround->padding.end(writingMode(), direction()); } ECursor cursor() const { return static_cast<ECursor>(inherited_flags._cursor_style); } CursorList* cursors() const { return rareInheritedData->cursorData.get(); } @@ -737,9 +762,9 @@ public: EBoxAlignment boxAlign() const { return static_cast<EBoxAlignment>(rareNonInheritedData->m_deprecatedFlexibleBox->align); } EBoxDirection boxDirection() const { return static_cast<EBoxDirection>(inherited_flags._box_direction); } float boxFlex() const { return rareNonInheritedData->m_deprecatedFlexibleBox->flex; } - unsigned int boxFlexGroup() const { return rareNonInheritedData->m_deprecatedFlexibleBox->flex_group; } + unsigned boxFlexGroup() const { return rareNonInheritedData->m_deprecatedFlexibleBox->flexGroup; } EBoxLines boxLines() const { return static_cast<EBoxLines>(rareNonInheritedData->m_deprecatedFlexibleBox->lines); } - unsigned int boxOrdinalGroup() const { return rareNonInheritedData->m_deprecatedFlexibleBox->ordinal_group; } + unsigned boxOrdinalGroup() const { return rareNonInheritedData->m_deprecatedFlexibleBox->ordinalGroup; } EBoxOrient boxOrient() const { return static_cast<EBoxOrient>(rareNonInheritedData->m_deprecatedFlexibleBox->orient); } EBoxPack boxPack() const { return static_cast<EBoxPack>(rareNonInheritedData->m_deprecatedFlexibleBox->pack); } @@ -747,18 +772,22 @@ public: const Vector<String>& callbackSelectors() const { return rareNonInheritedData->m_callbackSelectors; } float flexGrow() const { return rareNonInheritedData->m_flexibleBox->m_flexGrow; } float flexShrink() const { return rareNonInheritedData->m_flexibleBox->m_flexShrink; } - Length flexBasis() const { return rareNonInheritedData->m_flexibleBox->m_flexBasis; } + const Length& flexBasis() const { return rareNonInheritedData->m_flexibleBox->m_flexBasis; } EAlignContent alignContent() const { return static_cast<EAlignContent>(rareNonInheritedData->m_alignContent); } - EAlignItems alignItems() const { return static_cast<EAlignItems>(rareNonInheritedData->m_alignItems); } - EAlignItems alignSelf() const { return static_cast<EAlignItems>(rareNonInheritedData->m_alignSelf); } + ItemPosition alignItems() const { return static_cast<ItemPosition>(rareNonInheritedData->m_alignItems); } + OverflowAlignment alignItemsOverflowAlignment() const { return static_cast<OverflowAlignment>(rareNonInheritedData->m_alignItemsOverflowAlignment); } + ItemPosition alignSelf() const { return static_cast<ItemPosition>(rareNonInheritedData->m_alignSelf); } + OverflowAlignment alignSelfOverflowAlignment() const { return static_cast<OverflowAlignment>(rareNonInheritedData->m_alignSelfOverflowAlignment); } EFlexDirection flexDirection() const { return static_cast<EFlexDirection>(rareNonInheritedData->m_flexibleBox->m_flexDirection); } 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); } EJustifyContent justifyContent() const { return static_cast<EJustifyContent>(rareNonInheritedData->m_justifyContent); } + ItemPosition justifySelf() const { return static_cast<ItemPosition>(rareNonInheritedData->m_justifySelf); } + OverflowAlignment justifySelfOverflowAlignment() const { return static_cast<OverflowAlignment>(rareNonInheritedData->m_justifySelfOverflowAlignment); } - const Vector<GridTrackSize>& gridDefinitionColumns() const { return rareNonInheritedData->m_grid->m_gridDefinitionColumns; } - const Vector<GridTrackSize>& gridDefinitionRows() const { return rareNonInheritedData->m_grid->m_gridDefinitionRows; } + const Vector<GridTrackSize>& gridTemplateColumns() const { return rareNonInheritedData->m_grid->m_gridTemplateColumns; } + const Vector<GridTrackSize>& gridTemplateRows() const { return rareNonInheritedData->m_grid->m_gridTemplateRows; } const NamedGridLinesMap& namedGridColumnLines() const { return rareNonInheritedData->m_grid->m_namedGridColumnLines; } const NamedGridLinesMap& namedGridRowLines() const { return rareNonInheritedData->m_grid->m_namedGridRowLines; } const OrderedNamedGridLines& orderedNamedGridColumnLines() const { return rareNonInheritedData->m_grid->m_orderedNamedGridColumnLines; } @@ -785,8 +814,10 @@ public: EBoxDecorationBreak boxDecorationBreak() const { return m_box->boxDecorationBreak(); } StyleReflection* boxReflect() const { return rareNonInheritedData->m_boxReflect.get(); } + bool reflectionDataEquivalent(const RenderStyle* otherStyle) const { return rareNonInheritedData->reflectionDataEquivalent(*otherStyle->rareNonInheritedData); } + EBoxSizing boxSizing() const { return m_box->boxSizing(); } - Length marqueeIncrement() const { return rareNonInheritedData->m_marquee->increment; } + const Length& marqueeIncrement() const { return rareNonInheritedData->m_marquee->increment; } int marqueeSpeed() const { return rareNonInheritedData->m_marquee->speed; } int marqueeLoopCount() const { return rareNonInheritedData->m_marquee->loops; } EMarqueeBehavior marqueeBehavior() const { return static_cast<EMarqueeBehavior>(rareNonInheritedData->m_marquee->behavior); } @@ -805,18 +836,20 @@ public: const AtomicString& locale() const { return rareInheritedData->locale; } EBorderFit borderFit() const { return static_cast<EBorderFit>(rareNonInheritedData->m_borderFit); } EResize resize() const { return static_cast<EResize>(rareInheritedData->resize); } - ColumnAxis columnAxis() const { return static_cast<ColumnAxis>(rareNonInheritedData->m_multiCol->m_axis); } - bool hasInlineColumnAxis() const { - ColumnAxis axis = columnAxis(); - return axis == AutoColumnAxis || isHorizontalWritingMode() == (axis == HorizontalColumnAxis); + bool hasInlinePaginationAxis() const + { + // If the pagination axis is parallel with the writing mode inline axis, columns may be laid + // out along the inline axis, just like for regular multicol. Otherwise, we need to lay out + // along the block axis. + if (isOverflowPaged()) + return (overflowY() == OPAGEDX) == isHorizontalWritingMode(); + return false; } - ColumnProgression columnProgression() const { return static_cast<ColumnProgression>(rareNonInheritedData->m_multiCol->m_progression); } float columnWidth() const { return rareNonInheritedData->m_multiCol->m_width; } bool hasAutoColumnWidth() const { return rareNonInheritedData->m_multiCol->m_autoWidth; } unsigned short columnCount() const { return rareNonInheritedData->m_multiCol->m_count; } bool hasAutoColumnCount() const { return rareNonInheritedData->m_multiCol->m_autoCount; } - bool specifiesAutoColumns() const { return hasAutoColumnCount() && hasAutoColumnWidth(); } - bool specifiesColumns() const { return !hasAutoColumnCount() || !hasAutoColumnWidth() || !hasInlineColumnAxis(); } + bool specifiesColumns() const { return !hasAutoColumnCount() || !hasAutoColumnWidth(); } ColumnFill columnFill() const { return static_cast<ColumnFill>(rareNonInheritedData->m_multiCol->m_fill); } float columnGap() const { return rareNonInheritedData->m_multiCol->m_gap; } bool hasNormalColumnGap() const { return rareNonInheritedData->m_multiCol->m_normalGap; } @@ -827,14 +860,12 @@ public: EPageBreak columnBreakBefore() const { return static_cast<EPageBreak>(rareNonInheritedData->m_multiCol->m_breakBefore); } EPageBreak columnBreakInside() const { return static_cast<EPageBreak>(rareNonInheritedData->m_multiCol->m_breakInside); } EPageBreak columnBreakAfter() const { return static_cast<EPageBreak>(rareNonInheritedData->m_multiCol->m_breakAfter); } - EPageBreak regionBreakBefore() const { return static_cast<EPageBreak>(rareNonInheritedData->m_regionBreakBefore); } - EPageBreak regionBreakInside() const { return static_cast<EPageBreak>(rareNonInheritedData->m_regionBreakInside); } - EPageBreak regionBreakAfter() const { return static_cast<EPageBreak>(rareNonInheritedData->m_regionBreakAfter); } const TransformOperations& transform() const { return rareNonInheritedData->m_transform->m_operations; } - Length transformOriginX() const { return rareNonInheritedData->m_transform->m_x; } - Length transformOriginY() const { return rareNonInheritedData->m_transform->m_y; } + const Length& transformOriginX() const { return rareNonInheritedData->m_transform->m_x; } + const Length& transformOriginY() const { return rareNonInheritedData->m_transform->m_y; } float transformOriginZ() const { return rareNonInheritedData->m_transform->m_z; } bool hasTransform() const { return !rareNonInheritedData->m_transform->m_operations.operations().isEmpty(); } + bool transformDataEquivalent(const RenderStyle& otherStyle) const { return rareNonInheritedData->m_transform == otherStyle.rareNonInheritedData->m_transform; } TextEmphasisFill textEmphasisFill() const { return static_cast<TextEmphasisFill>(rareInheritedData->textEmphasisFill); } TextEmphasisMark textEmphasisMark() const; @@ -866,30 +897,16 @@ public: // End CSS3 Getters - const AtomicString& flowThread() const { return rareNonInheritedData->m_flowThread; } - bool hasFlowFrom() const { return !rareNonInheritedData->m_regionThread.isNull(); } - const AtomicString& regionThread() const { return rareNonInheritedData->m_regionThread; } - RegionFragment regionFragment() const { return static_cast<RegionFragment>(rareNonInheritedData->m_regionFragment); } - - const AtomicString& lineGrid() const { return rareInheritedData->m_lineGrid; } - LineSnap lineSnap() const { return static_cast<LineSnap>(rareInheritedData->m_lineSnap); } - LineAlign lineAlign() const { return static_cast<LineAlign>(rareInheritedData->m_lineAlign); } - WrapFlow wrapFlow() const { return static_cast<WrapFlow>(rareNonInheritedData->m_wrapFlow); } WrapThrough wrapThrough() const { return static_cast<WrapThrough>(rareNonInheritedData->m_wrapThrough); } // Apple-specific property getter methods EPointerEvents pointerEvents() const { return static_cast<EPointerEvents>(inherited_flags._pointerEvents); } - const CSSAnimationDataList* animations() const { return rareNonInheritedData->m_animations.get(); } - const CSSAnimationDataList* transitions() const { return rareNonInheritedData->m_transitions.get(); } + const CSSAnimationData* animations() const { return rareNonInheritedData->m_animations.get(); } + const CSSTransitionData* transitions() const { return rareNonInheritedData->m_transitions.get(); } - CSSAnimationDataList* accessAnimations(); - CSSAnimationDataList* accessTransitions(); - - bool hasAnimations() const { return rareNonInheritedData->m_animations && rareNonInheritedData->m_animations->size() > 0; } - - // return the first found Animation (including 'all' transitions) - const CSSAnimationData* transitionForProperty(CSSPropertyID) const; + CSSAnimationData& accessAnimations(); + CSSTransitionData& accessTransitions(); ETransformStyle3D transformStyle3D() const { return static_cast<ETransformStyle3D>(rareNonInheritedData->m_transformStyle3D); } bool preserves3D() const { return rareNonInheritedData->m_transformStyle3D == TransformStyle3DPreserve3D; } @@ -897,13 +914,20 @@ public: EBackfaceVisibility backfaceVisibility() const { return static_cast<EBackfaceVisibility>(rareNonInheritedData->m_backfaceVisibility); } float perspective() const { return rareNonInheritedData->m_perspective; } bool hasPerspective() const { return rareNonInheritedData->m_perspective > 0; } - Length perspectiveOriginX() const { return rareNonInheritedData->m_perspectiveOriginX; } - Length perspectiveOriginY() const { return rareNonInheritedData->m_perspectiveOriginY; } - LengthSize pageSize() const { return rareNonInheritedData->m_pageSize; } + const Length& perspectiveOriginX() const { return rareNonInheritedData->m_perspectiveOriginX; } + const Length& perspectiveOriginY() const { return rareNonInheritedData->m_perspectiveOriginY; } + const LengthSize& pageSize() const { return rareNonInheritedData->m_pageSize; } PageSizeType pageSizeType() const { return static_cast<PageSizeType>(rareNonInheritedData->m_pageSizeType); } - // When set, this ensures that styles compare as different. Used during accelerated animations. - bool isRunningAcceleratedAnimation() const { return rareNonInheritedData->m_runningAcceleratedAnimation; } + bool hasCurrentOpacityAnimation() const { return rareNonInheritedData->m_hasCurrentOpacityAnimation; } + bool hasCurrentTransformAnimation() const { return rareNonInheritedData->m_hasCurrentTransformAnimation; } + bool hasCurrentFilterAnimation() const { return rareNonInheritedData->m_hasCurrentFilterAnimation; } + bool shouldCompositeForCurrentAnimations() { return hasCurrentOpacityAnimation() || hasCurrentTransformAnimation() || hasCurrentFilterAnimation(); } + + bool isRunningOpacityAnimationOnCompositor() const { return rareNonInheritedData->m_runningOpacityAnimationOnCompositor; } + bool isRunningTransformAnimationOnCompositor() const { return rareNonInheritedData->m_runningTransformAnimationOnCompositor; } + bool isRunningFilterAnimationOnCompositor() const { return rareNonInheritedData->m_runningFilterAnimationOnCompositor; } + bool isRunningAnimationOnCompositor() { return isRunningOpacityAnimationOnCompositor() || isRunningTransformAnimationOnCompositor() || isRunningFilterAnimationOnCompositor(); } LineBoxContain lineBoxContain() const { return rareInheritedData->m_lineBoxContain; } const LineClampValue& lineClamp() const { return rareNonInheritedData->lineClamp; } @@ -936,6 +960,14 @@ public: TouchAction touchAction() const { return static_cast<TouchAction>(rareNonInheritedData->m_touchAction); } TouchActionDelay touchActionDelay() const { return static_cast<TouchActionDelay>(rareInheritedData->m_touchActionDelay); } + ScrollBehavior scrollBehavior() const { return static_cast<ScrollBehavior>(rareNonInheritedData->m_scrollBehavior); } + + const Vector<CSSPropertyID>& willChangeProperties() const { return rareNonInheritedData->m_willChange->m_properties; } + bool willChangeContents() const { return rareNonInheritedData->m_willChange->m_contents; } + bool willChangeScrollPosition() const { return rareNonInheritedData->m_willChange->m_scrollPosition; } + bool hasWillChangeCompositingHint() const; + bool subtreeWillChangeContents() const { return rareInheritedData->m_subtreeWillChangeContents; } + // attribute setter methods void setDisplay(EDisplay v) { noninherited_flags._effectiveDisplay = v; } @@ -943,15 +975,15 @@ public: void setPosition(EPosition v) { noninherited_flags._position = v; } void setFloating(EFloat v) { noninherited_flags._floating = v; } - void setLeft(Length v) { SET_VAR(surround, offset.m_left, v); } - void setRight(Length v) { SET_VAR(surround, offset.m_right, v); } - void setTop(Length v) { SET_VAR(surround, offset.m_top, v); } - void setBottom(Length v) { SET_VAR(surround, offset.m_bottom, v); } + void setLeft(const Length& v) { SET_VAR(surround, offset.m_left, v); } + void setRight(const Length& v) { SET_VAR(surround, offset.m_right, v); } + void setTop(const Length& v) { SET_VAR(surround, offset.m_top, v); } + void setBottom(const Length& v) { SET_VAR(surround, offset.m_bottom, v); } - void setWidth(Length v) { SET_VAR(m_box, m_width, v); } - void setHeight(Length v) { SET_VAR(m_box, m_height, v); } + void setWidth(const Length& v) { SET_VAR(m_box, m_width, v); } + void setHeight(const Length& v) { SET_VAR(m_box, m_height, v); } - void setLogicalWidth(Length v) + void setLogicalWidth(const Length& v) { if (isHorizontalWritingMode()) { SET_VAR(m_box, m_width, v); @@ -960,7 +992,7 @@ public: } } - void setLogicalHeight(Length v) + void setLogicalHeight(const Length& v) { if (isHorizontalWritingMode()) { SET_VAR(m_box, m_height, v); @@ -969,45 +1001,55 @@ public: } } - void setMinWidth(Length v) { SET_VAR(m_box, m_minWidth, v); } - void setMaxWidth(Length v) { SET_VAR(m_box, m_maxWidth, v); } - void setMinHeight(Length v) { SET_VAR(m_box, m_minHeight, v); } - void setMaxHeight(Length v) { SET_VAR(m_box, m_maxHeight, v); } + void setMinWidth(const Length& v) { SET_VAR(m_box, m_minWidth, v); } + void setMaxWidth(const Length& v) { SET_VAR(m_box, m_maxWidth, v); } + void setMinHeight(const Length& v) { SET_VAR(m_box, m_minHeight, v); } + void setMaxHeight(const Length& v) { SET_VAR(m_box, m_maxHeight, v); } DraggableRegionMode getDraggableRegionMode() const { return rareNonInheritedData->m_draggableRegionMode; } void setDraggableRegionMode(DraggableRegionMode v) { SET_VAR(rareNonInheritedData, m_draggableRegionMode, v); } - void resetBorder() { resetBorderImage(); resetBorderTop(); resetBorderRight(); resetBorderBottom(); resetBorderLeft(); resetBorderRadius(); } + void resetBorder() + { + resetBorderImage(); + resetBorderTop(); + resetBorderRight(); + resetBorderBottom(); + resetBorderLeft(); + resetBorderTopLeftRadius(); + resetBorderTopRightRadius(); + resetBorderBottomLeftRadius(); + resetBorderBottomRightRadius(); + } void resetBorderTop() { SET_VAR(surround, border.m_top, BorderValue()); } void resetBorderRight() { SET_VAR(surround, border.m_right, BorderValue()); } void resetBorderBottom() { SET_VAR(surround, border.m_bottom, BorderValue()); } void resetBorderLeft() { SET_VAR(surround, border.m_left, BorderValue()); } void resetBorderImage() { SET_VAR(surround, border.m_image, NinePieceImage()); } - void resetBorderRadius() { resetBorderTopLeftRadius(); resetBorderTopRightRadius(); resetBorderBottomLeftRadius(); resetBorderBottomRightRadius(); } void resetBorderTopLeftRadius() { SET_VAR(surround, border.m_topLeft, initialBorderRadius()); } void resetBorderTopRightRadius() { SET_VAR(surround, border.m_topRight, initialBorderRadius()); } void resetBorderBottomLeftRadius() { SET_VAR(surround, border.m_bottomLeft, initialBorderRadius()); } void resetBorderBottomRightRadius() { SET_VAR(surround, border.m_bottomRight, initialBorderRadius()); } - void setBackgroundColor(const Color& v) { SET_VAR(m_background, m_color, v); } + void setBackgroundColor(const StyleColor& v) { SET_VAR(m_background, m_color, v); } - void setBackgroundXPosition(Length length) { SET_VAR(m_background, m_background.m_xPosition, length); } - void setBackgroundYPosition(Length length) { SET_VAR(m_background, m_background.m_yPosition, length); } + void setBackgroundXPosition(const Length& length) { SET_VAR(m_background, m_background.m_xPosition, length); } + void setBackgroundYPosition(const Length& length) { SET_VAR(m_background, m_background.m_yPosition, length); } void setBackgroundSize(EFillSizeType b) { SET_VAR(m_background, m_background.m_sizeType, b); } - void setBackgroundSizeLength(LengthSize s) { SET_VAR(m_background, m_background.m_sizeLength, s); } + void setBackgroundSizeLength(const LengthSize& s) { SET_VAR(m_background, m_background.m_sizeLength, s); } void setBorderImage(const NinePieceImage& b) { SET_VAR(surround, border.m_image, b); } void setBorderImageSource(PassRefPtr<StyleImage>); - void setBorderImageSlices(LengthBox); + void setBorderImageSlices(const LengthBox&); void setBorderImageWidth(const BorderImageLengthBox&); void setBorderImageOutset(const BorderImageLengthBox&); - void setBorderTopLeftRadius(LengthSize s) { SET_VAR(surround, border.m_topLeft, s); } - void setBorderTopRightRadius(LengthSize s) { SET_VAR(surround, border.m_topRight, s); } - void setBorderBottomLeftRadius(LengthSize s) { SET_VAR(surround, border.m_bottomLeft, s); } - void setBorderBottomRightRadius(LengthSize s) { SET_VAR(surround, border.m_bottomRight, s); } + void setBorderTopLeftRadius(const LengthSize& s) { SET_VAR(surround, border.m_topLeft, s); } + void setBorderTopRightRadius(const LengthSize& s) { SET_VAR(surround, border.m_topRight, s); } + void setBorderBottomLeftRadius(const LengthSize& s) { SET_VAR(surround, border.m_bottomLeft, s); } + void setBorderBottomRightRadius(const LengthSize& s) { SET_VAR(surround, border.m_bottomRight, s); } - void setBorderRadius(LengthSize s) + void setBorderRadius(const LengthSize& s) { setBorderTopLeftRadius(s); setBorderTopRightRadius(s); @@ -1019,7 +1061,7 @@ public: setBorderRadius(LengthSize(Length(s.width(), Fixed), Length(s.height(), Fixed))); } - RoundedRect getRoundedBorderFor(const LayoutRect& borderRect, RenderView* = 0, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const; + RoundedRect getRoundedBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const; RoundedRect getRoundedInnerBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const; RoundedRect getRoundedInnerBorderFor(const LayoutRect& borderRect, @@ -1027,35 +1069,35 @@ 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_BORDERVALUE_COLOR(surround, border.m_left, v); } + void setBorderLeftColor(const StyleColor& 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_BORDERVALUE_COLOR(surround, border.m_right, v); } + void setBorderRightColor(const StyleColor& 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_BORDERVALUE_COLOR(surround, border.m_top, v); } + void setBorderTopColor(const StyleColor& 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_BORDERVALUE_COLOR(surround, border.m_bottom, v); } + void setBorderBottomColor(const StyleColor& 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_BORDERVALUE_COLOR(m_background, m_outline, v); } + void setOutlineColor(const StyleColor& 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; } void setVisibility(EVisibility v) { inherited_flags._visibility = v; } void setVerticalAlign(EVerticalAlign v) { noninherited_flags._vertical_align = v; } - void setVerticalAlignLength(Length length) { setVerticalAlign(LENGTH); SET_VAR(m_box, m_verticalAlign, length); } + void setVerticalAlignLength(const Length& length) { setVerticalAlign(LENGTH); SET_VAR(m_box, m_verticalAlign, length); } void setHasClip(bool b = true) { SET_VAR(visual, hasClip, b); } - void setClipLeft(Length v) { SET_VAR(visual, clip.m_left, v); } - void setClipRight(Length v) { SET_VAR(visual, clip.m_right, v); } - void setClipTop(Length v) { SET_VAR(visual, clip.m_top, v); } - void setClipBottom(Length v) { SET_VAR(visual, clip.m_bottom, v); } - void setClip(Length top, Length right, Length bottom, Length left); - void setClip(LengthBox box) { SET_VAR(visual, clip, box); } + void setClipLeft(const Length& v) { SET_VAR(visual, clip.m_left, v); } + void setClipRight(const Length& v) { SET_VAR(visual, clip.m_right, v); } + void setClipTop(const Length& v) { SET_VAR(visual, clip.m_top, v); } + void setClipBottom(const Length& v) { SET_VAR(visual, clip.m_bottom, v); } + void setClip(const Length& top, const Length& right, const Length& bottom, const Length& left); + void setClip(const LengthBox& box) { SET_VAR(visual, clip, box); } void setUnicodeBidi(EUnicodeBidi b) { noninherited_flags._unicodeBidi = b; } @@ -1065,41 +1107,40 @@ public: bool setFontDescription(const FontDescription&); // Only used for blending font sizes when animating and for text autosizing. void setFontSize(float); + void setFontWeight(FontWeight); void setTextAutosizingMultiplier(float v) { - SET_VAR(visual, m_textAutosizingMultiplier, v); + SET_VAR(inherited, textAutosizingMultiplier, v); setFontSize(fontDescription().specifiedSize()); } void setColor(const Color&); - void setTextIndent(Length v) { SET_VAR(rareInheritedData, indent, v); } + void setTextIndent(const Length& v) { SET_VAR(rareInheritedData, indent, v); } void setTextIndentLine(TextIndentLine v) { SET_VAR(rareInheritedData, m_textIndentLine, v); } + void setTextIndentType(TextIndentType v) { SET_VAR(rareInheritedData, m_textIndentType, v); } void setTextAlign(ETextAlign v) { inherited_flags._text_align = v; } void setTextAlignLast(TextAlignLast v) { SET_VAR(rareInheritedData, m_textAlignLast, v); } void setTextJustify(TextJustify v) { SET_VAR(rareInheritedData, m_textJustify, v); } void setTextTransform(ETextTransform v) { inherited_flags._text_transform = v; } - void addToTextDecorationsInEffect(TextDecoration v) { inherited_flags._text_decorations |= v; } - void setTextDecorationsInEffect(TextDecoration v) { inherited_flags._text_decorations = v; } + void applyTextDecorations(); + void clearAppliedTextDecorations(); void setTextDecoration(TextDecoration v) { SET_VAR(visual, textDecoration, v); } void setTextUnderlinePosition(TextUnderlinePosition v) { SET_VAR(rareInheritedData, m_textUnderlinePosition, v); } void setTextDecorationStyle(TextDecorationStyle v) { SET_VAR(rareNonInheritedData, m_textDecorationStyle, v); } void setDirection(TextDirection v) { inherited_flags._direction = v; } - void setLineHeight(Length specifiedLineHeight); + void setLineHeight(const Length& specifiedLineHeight); bool setZoom(float); - void setZoomWithoutReturnValue(float f) { setZoom(f); } bool setEffectiveZoom(float); void setImageRendering(EImageRendering v) { SET_VAR(rareInheritedData, m_imageRendering, v); } void setWhiteSpace(EWhiteSpace v) { inherited_flags._white_space = v; } + // FIXME: Remove these two and replace them with respective FontBuilder calls. void setWordSpacing(float); void setLetterSpacing(float); - void clearBackgroundLayers() { m_background.access()->m_background = FillLayer(BackgroundFillLayer); } - void inheritBackgroundLayers(const FillLayer& parent) { m_background.access()->m_background = parent; } - void adjustBackgroundLayers() { if (backgroundLayers()->next()) { @@ -1108,9 +1149,6 @@ public: } } - void clearMaskLayers() { rareNonInheritedData.access()->m_mask = FillLayer(MaskFillLayer); } - void inheritMaskLayers(const FillLayer& parent) { rareNonInheritedData.access()->m_mask = parent; } - void adjustMaskLayers() { if (maskLayers()->next()) { @@ -1123,7 +1161,7 @@ public: void setMaskBoxImage(const NinePieceImage& b) { SET_VAR(rareNonInheritedData, m_maskBoxImage, b); } void setMaskBoxImageSource(PassRefPtr<StyleImage> v) { rareNonInheritedData.access()->m_maskBoxImage.setImage(v); } - void setMaskBoxImageSlices(LengthBox slices) + void setMaskBoxImageSlices(const LengthBox& slices) { rareNonInheritedData.access()->m_maskBoxImage.setImageSlices(slices); } @@ -1139,9 +1177,9 @@ public: { rareNonInheritedData.access()->m_maskBoxImage.setOutset(outset); } - void setMaskXPosition(Length length) { SET_VAR(rareNonInheritedData, m_mask.m_xPosition, length); } - void setMaskYPosition(Length length) { SET_VAR(rareNonInheritedData, m_mask.m_yPosition, length); } - void setMaskSize(LengthSize s) { SET_VAR(rareNonInheritedData, m_mask.m_sizeLength, s); } + void setMaskXPosition(const Length& length) { SET_VAR(rareNonInheritedData, m_mask.m_xPosition, length); } + void setMaskYPosition(const Length& length) { SET_VAR(rareNonInheritedData, m_mask.m_yPosition, length); } + void setMaskSize(const LengthSize& s) { SET_VAR(rareNonInheritedData, m_mask.m_sizeLength, s); } void setBorderCollapse(EBorderCollapse collapse) { inherited_flags._border_collapse = collapse; } void setHorizontalBorderSpacing(short); @@ -1157,20 +1195,19 @@ public: void setListStyleImage(PassRefPtr<StyleImage>); void setListStylePosition(EListStylePosition v) { inherited_flags._list_style_position = v; } - void resetMargin() { SET_VAR(surround, margin, LengthBox(Fixed)); } - void setMarginTop(Length v) { SET_VAR(surround, margin.m_top, v); } - void setMarginBottom(Length v) { SET_VAR(surround, margin.m_bottom, v); } - void setMarginLeft(Length v) { SET_VAR(surround, margin.m_left, v); } - void setMarginRight(Length v) { SET_VAR(surround, margin.m_right, v); } - void setMarginStart(Length); - void setMarginEnd(Length); + void setMarginTop(const Length& v) { SET_VAR(surround, margin.m_top, v); } + void setMarginBottom(const Length& v) { SET_VAR(surround, margin.m_bottom, v); } + void setMarginLeft(const Length& v) { SET_VAR(surround, margin.m_left, v); } + void setMarginRight(const Length& v) { SET_VAR(surround, margin.m_right, v); } + void setMarginStart(const Length&); + void setMarginEnd(const Length&); void resetPadding() { SET_VAR(surround, padding, LengthBox(Auto)); } void setPaddingBox(const LengthBox& b) { SET_VAR(surround, padding, b); } - void setPaddingTop(Length v) { SET_VAR(surround, padding.m_top, v); } - void setPaddingBottom(Length v) { SET_VAR(surround, padding.m_bottom, v); } - void setPaddingLeft(Length v) { SET_VAR(surround, padding.m_left, v); } - void setPaddingRight(Length v) { SET_VAR(surround, padding.m_right, v); } + void setPaddingTop(const Length& v) { SET_VAR(surround, padding.m_top, v); } + void setPaddingBottom(const Length& v) { SET_VAR(surround, padding.m_bottom, v); } + void setPaddingLeft(const Length& v) { SET_VAR(surround, padding.m_left, v); } + void setPaddingRight(const Length& v) { SET_VAR(surround, padding.m_right, v); } void setCursor(ECursor c) { inherited_flags._cursor_style = c; } void addCursor(PassRefPtr<StyleImage>, const IntPoint& hotSpot = IntPoint()); @@ -1202,9 +1239,9 @@ public: // CSS3 Setters void setOutlineOffset(int v) { SET_VAR(m_background, m_outline.m_offset, v); } void setTextShadow(PassRefPtr<ShadowList>); - void setTextStrokeColor(const Color& c) { SET_VAR(rareInheritedData, textStrokeColor, c); } + void setTextStrokeColor(const StyleColor& c) { SET_VAR_WITH_SETTER(rareInheritedData, textStrokeColor, setTextStrokeColor, c); } void setTextStrokeWidth(float w) { SET_VAR(rareInheritedData, textStrokeWidth, w); } - void setTextFillColor(const Color& c) { SET_VAR(rareInheritedData, textFillColor, c); } + void setTextFillColor(const StyleColor& c) { SET_VAR_WITH_SETTER(rareInheritedData, textFillColor, setTextFillColor, c); } 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 @@ -1212,9 +1249,9 @@ public: void setBoxDecorationBreak(EBoxDecorationBreak b) { SET_VAR(m_box, m_boxDecorationBreak, b); } void setBoxDirection(EBoxDirection d) { inherited_flags._box_direction = d; } void setBoxFlex(float f) { SET_VAR(rareNonInheritedData.access()->m_deprecatedFlexibleBox, flex, f); } - void setBoxFlexGroup(unsigned int fg) { SET_VAR(rareNonInheritedData.access()->m_deprecatedFlexibleBox, flex_group, fg); } + void setBoxFlexGroup(unsigned fg) { SET_VAR(rareNonInheritedData.access()->m_deprecatedFlexibleBox, flexGroup, fg); } void setBoxLines(EBoxLines l) { SET_VAR(rareNonInheritedData.access()->m_deprecatedFlexibleBox, lines, l); } - void setBoxOrdinalGroup(unsigned int og) { SET_VAR(rareNonInheritedData.access()->m_deprecatedFlexibleBox, ordinal_group, og); } + void setBoxOrdinalGroup(unsigned og) { SET_VAR(rareNonInheritedData.access()->m_deprecatedFlexibleBox, ordinalGroup, og); } void setBoxOrient(EBoxOrient o) { SET_VAR(rareNonInheritedData.access()->m_deprecatedFlexibleBox, orient, o); } void setBoxPack(EBoxPack p) { SET_VAR(rareNonInheritedData.access()->m_deprecatedFlexibleBox, pack, p); } void setBoxShadow(PassRefPtr<ShadowList>); @@ -1222,19 +1259,24 @@ public: void setBoxSizing(EBoxSizing s) { SET_VAR(m_box, m_boxSizing, s); } void setFlexGrow(float f) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_flexGrow, f); } void setFlexShrink(float f) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_flexShrink, f); } - void setFlexBasis(Length length) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_flexBasis, length); } - void setOrder(int o) { SET_VAR(rareNonInheritedData, m_order, o); } + void setFlexBasis(const Length& length) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_flexBasis, length); } + // We restrict the smallest value to int min + 2 because we use int min and int min + 1 as special values in a hash set. + void setOrder(int o) { SET_VAR(rareNonInheritedData, m_order, max(std::numeric_limits<int>::min() + 2, o)); } void addCallbackSelector(const String& selector); void setAlignContent(EAlignContent p) { SET_VAR(rareNonInheritedData, m_alignContent, p); } - void setAlignItems(EAlignItems a) { SET_VAR(rareNonInheritedData, m_alignItems, a); } - void setAlignSelf(EAlignItems a) { SET_VAR(rareNonInheritedData, m_alignSelf, a); } + void setAlignItems(ItemPosition a) { SET_VAR(rareNonInheritedData, m_alignItems, a); } + void setAlignItemsOverflowAlignment(OverflowAlignment overflowAlignment) { SET_VAR(rareNonInheritedData, m_alignItemsOverflowAlignment, overflowAlignment); } + void setAlignSelf(ItemPosition a) { SET_VAR(rareNonInheritedData, m_alignSelf, a); } + void setAlignSelfOverflowAlignment(OverflowAlignment overflowAlignment) { SET_VAR(rareNonInheritedData, m_alignSelfOverflowAlignment, overflowAlignment); } 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 setJustifyContent(EJustifyContent p) { SET_VAR(rareNonInheritedData, m_justifyContent, p); } + void setJustifySelf(ItemPosition justifySelf) { SET_VAR(rareNonInheritedData, m_justifySelf, justifySelf); } + void setJustifySelfOverflowAlignment(OverflowAlignment overflowAlignment) { SET_VAR(rareNonInheritedData, m_justifySelfOverflowAlignment, overflowAlignment); } void setGridAutoColumns(const GridTrackSize& length) { SET_VAR(rareNonInheritedData.access()->m_grid, m_gridAutoColumns, length); } void setGridAutoRows(const GridTrackSize& length) { SET_VAR(rareNonInheritedData.access()->m_grid, m_gridAutoRows, length); } - void setGridDefinitionColumns(const Vector<GridTrackSize>& lengths) { SET_VAR(rareNonInheritedData.access()->m_grid, m_gridDefinitionColumns, lengths); } - void setGridDefinitionRows(const Vector<GridTrackSize>& lengths) { SET_VAR(rareNonInheritedData.access()->m_grid, m_gridDefinitionRows, lengths); } + void setGridTemplateColumns(const Vector<GridTrackSize>& lengths) { SET_VAR(rareNonInheritedData.access()->m_grid, m_gridTemplateColumns, lengths); } + void setGridTemplateRows(const Vector<GridTrackSize>& lengths) { SET_VAR(rareNonInheritedData.access()->m_grid, m_gridTemplateRows, lengths); } void setNamedGridColumnLines(const NamedGridLinesMap& namedGridColumnLines) { SET_VAR(rareNonInheritedData.access()->m_grid, m_namedGridColumnLines, namedGridColumnLines); } void setNamedGridRowLines(const NamedGridLinesMap& namedGridRowLines) { SET_VAR(rareNonInheritedData.access()->m_grid, m_namedGridRowLines, namedGridRowLines); } void setOrderedNamedGridColumnLines(const OrderedNamedGridLines& orderedNamedGridColumnLines) { SET_VAR(rareNonInheritedData.access()->m_grid, m_orderedNamedGridColumnLines, orderedNamedGridColumnLines); } @@ -1249,7 +1291,7 @@ public: void setGridRowStart(const GridPosition& rowStartPosition) { SET_VAR(rareNonInheritedData.access()->m_gridItem, m_gridRowStart, rowStartPosition); } void setGridRowEnd(const GridPosition& rowEndPosition) { SET_VAR(rareNonInheritedData.access()->m_gridItem, m_gridRowEnd, rowEndPosition); } - void setMarqueeIncrement(Length f) { SET_VAR(rareNonInheritedData.access()->m_marquee, increment, f); } + void setMarqueeIncrement(const Length& f) { SET_VAR(rareNonInheritedData.access()->m_marquee, increment, f); } void setMarqueeSpeed(int f) { SET_VAR(rareNonInheritedData.access()->m_marquee, speed, f); } void setMarqueeDirection(EMarqueeDirection d) { SET_VAR(rareNonInheritedData.access()->m_marquee, direction, d); } void setMarqueeBehavior(EMarqueeBehavior b) { SET_VAR(rareNonInheritedData.access()->m_marquee, behavior, b); } @@ -1269,8 +1311,6 @@ public: void setLocale(const AtomicString& locale) { SET_VAR(rareInheritedData, locale, locale); } void setBorderFit(EBorderFit b) { SET_VAR(rareNonInheritedData, m_borderFit, b); } void setResize(EResize r) { SET_VAR(rareInheritedData, resize, r); } - void setColumnAxis(ColumnAxis axis) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_axis, axis); } - void setColumnProgression(ColumnProgression progression) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_progression, progression); } void setColumnWidth(float f) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_autoWidth, false); SET_VAR(rareNonInheritedData.access()->m_multiCol, m_width, f); } void setHasAutoColumnWidth() { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_autoWidth, true); SET_VAR(rareNonInheritedData.access()->m_multiCol, m_width, 0); } void setColumnCount(unsigned short c) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_autoCount, false); SET_VAR(rareNonInheritedData.access()->m_multiCol, m_count, c); } @@ -1278,7 +1318,7 @@ public: void setColumnFill(ColumnFill columnFill) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_fill, columnFill); } 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_BORDERVALUE_COLOR(rareNonInheritedData.access()->m_multiCol, m_rule, c); } + void setColumnRuleColor(const StyleColor& 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()); } @@ -1287,18 +1327,15 @@ public: // For valid values of column-break-inside see http://www.w3.org/TR/css3-multicol/#break-before-break-after-break-inside void setColumnBreakInside(EPageBreak p) { ASSERT(p == PBAUTO || p == PBAVOID); SET_VAR(rareNonInheritedData.access()->m_multiCol, m_breakInside, p); } void setColumnBreakAfter(EPageBreak p) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_breakAfter, p); } - void setRegionBreakBefore(EPageBreak p) { SET_VAR(rareNonInheritedData, m_regionBreakBefore, p); } - void setRegionBreakInside(EPageBreak p) { ASSERT(p == PBAUTO || p == PBAVOID); SET_VAR(rareNonInheritedData, m_regionBreakInside, p); } - void setRegionBreakAfter(EPageBreak p) { SET_VAR(rareNonInheritedData, m_regionBreakAfter, p); } void inheritColumnPropertiesFrom(RenderStyle* parent) { rareNonInheritedData.access()->m_multiCol = parent->rareNonInheritedData->m_multiCol; } void setTransform(const TransformOperations& ops) { SET_VAR(rareNonInheritedData.access()->m_transform, m_operations, ops); } - void setTransformOriginX(Length l) { SET_VAR(rareNonInheritedData.access()->m_transform, m_x, l); } - void setTransformOriginY(Length l) { SET_VAR(rareNonInheritedData.access()->m_transform, m_y, l); } + void setTransformOriginX(const Length& l) { SET_VAR(rareNonInheritedData.access()->m_transform, m_x, l); } + void setTransformOriginY(const Length& l) { SET_VAR(rareNonInheritedData.access()->m_transform, m_y, l); } void setTransformOriginZ(float f) { SET_VAR(rareNonInheritedData.access()->m_transform, m_z, f); } void setSpeak(ESpeak s) { SET_VAR(rareInheritedData, speak, s); } void setTextCombine(TextCombine v) { SET_VAR(rareNonInheritedData, m_textCombine, v); } - void setTextDecorationColor(const Color& c) { SET_VAR(rareNonInheritedData, m_textDecorationColor, c); } - void setTextEmphasisColor(const Color& c) { SET_VAR(rareInheritedData, textEmphasisColor, c); } + void setTextDecorationColor(const StyleColor& c) { SET_VAR(rareNonInheritedData, m_textDecorationColor, c); } + void setTextEmphasisColor(const StyleColor& c) { SET_VAR_WITH_SETTER(rareInheritedData, textEmphasisColor, setTextEmphasisColor, c); } void setTextEmphasisFill(TextEmphasisFill fill) { SET_VAR(rareInheritedData, textEmphasisFill, fill); } void setTextEmphasisMark(TextEmphasisMark mark) { SET_VAR(rareInheritedData, textEmphasisMark, mark); } void setTextEmphasisCustomMark(const AtomicString& mark) { SET_VAR(rareInheritedData, textEmphasisCustomMark, mark); } @@ -1316,14 +1353,6 @@ public: // End CSS3 Setters - void setLineGrid(const AtomicString& lineGrid) { SET_VAR(rareInheritedData, m_lineGrid, lineGrid); } - void setLineSnap(LineSnap lineSnap) { SET_VAR(rareInheritedData, m_lineSnap, lineSnap); } - void setLineAlign(LineAlign lineAlign) { SET_VAR(rareInheritedData, m_lineAlign, lineAlign); } - - void setFlowThread(const AtomicString& flowThread) { SET_VAR(rareNonInheritedData, m_flowThread, flowThread); } - void setRegionThread(const AtomicString& regionThread) { SET_VAR(rareNonInheritedData, m_regionThread, regionThread); } - void setRegionFragment(RegionFragment regionFragment) { SET_VAR(rareNonInheritedData, m_regionFragment, regionFragment); } - void setWrapFlow(WrapFlow wrapFlow) { SET_VAR(rareNonInheritedData, m_wrapFlow, wrapFlow); } void setWrapThrough(WrapThrough wrapThrough) { SET_VAR(rareNonInheritedData, m_wrapThrough, wrapThrough); } @@ -1340,19 +1369,22 @@ public: rareNonInheritedData.access()->m_transitions.clear(); } - void adjustAnimations(); - void adjustTransitions(); - void setTransformStyle3D(ETransformStyle3D b) { SET_VAR(rareNonInheritedData, m_transformStyle3D, b); } void setBackfaceVisibility(EBackfaceVisibility b) { SET_VAR(rareNonInheritedData, m_backfaceVisibility, b); } void setPerspective(float p) { SET_VAR(rareNonInheritedData, m_perspective, p); } - void setPerspectiveOriginX(Length l) { SET_VAR(rareNonInheritedData, m_perspectiveOriginX, l); } - void setPerspectiveOriginY(Length l) { SET_VAR(rareNonInheritedData, m_perspectiveOriginY, l); } - void setPageSize(LengthSize s) { SET_VAR(rareNonInheritedData, m_pageSize, s); } + void setPerspectiveOriginX(const Length& l) { SET_VAR(rareNonInheritedData, m_perspectiveOriginX, l); } + void setPerspectiveOriginY(const Length& l) { SET_VAR(rareNonInheritedData, m_perspectiveOriginY, l); } + void setPageSize(const LengthSize& s) { SET_VAR(rareNonInheritedData, m_pageSize, s); } void setPageSizeType(PageSizeType t) { SET_VAR(rareNonInheritedData, m_pageSizeType, t); } void resetPageSizeType() { SET_VAR(rareNonInheritedData, m_pageSizeType, PAGE_SIZE_AUTO); } - void setIsRunningAcceleratedAnimation(bool b = true) { SET_VAR(rareNonInheritedData, m_runningAcceleratedAnimation, b); } + void setHasCurrentOpacityAnimation(bool b = true) { SET_VAR(rareNonInheritedData, m_hasCurrentOpacityAnimation, b); } + void setHasCurrentTransformAnimation(bool b = true) { SET_VAR(rareNonInheritedData, m_hasCurrentTransformAnimation, b); } + void setHasCurrentFilterAnimation(bool b = true) { SET_VAR(rareNonInheritedData, m_hasCurrentFilterAnimation, b); } + + void setIsRunningOpacityAnimationOnCompositor(bool b = true) { SET_VAR(rareNonInheritedData, m_runningOpacityAnimationOnCompositor, b); } + void setIsRunningTransformAnimationOnCompositor(bool b = true) { SET_VAR(rareNonInheritedData, m_runningTransformAnimationOnCompositor, b); } + void setIsRunningFilterAnimationOnCompositor(bool b = true) { SET_VAR(rareNonInheritedData, m_runningFilterAnimationOnCompositor, b); } void setLineBoxContain(LineBoxContain c) { SET_VAR(rareInheritedData, m_lineBoxContain, c); } void setLineClamp(LineClampValue c) { SET_VAR(rareNonInheritedData, lineClamp, c); } @@ -1361,6 +1393,16 @@ public: void setTouchAction(TouchAction t) { SET_VAR(rareNonInheritedData, m_touchAction, t); } void setTouchActionDelay(TouchActionDelay t) { SET_VAR(rareInheritedData, m_touchActionDelay, t); } + void setScrollBehavior(ScrollBehavior b) { SET_VAR(rareNonInheritedData, m_scrollBehavior, b); } + + void setWillChangeProperties(const Vector<CSSPropertyID>& properties) { SET_VAR(rareNonInheritedData.access()->m_willChange, m_properties, properties); } + void setWillChangeContents(bool b) { SET_VAR(rareNonInheritedData.access()->m_willChange, m_contents, b); } + void setWillChangeScrollPosition(bool b) { SET_VAR(rareNonInheritedData.access()->m_willChange, m_scrollPosition, b); } + void setSubtreeWillChangeContents(bool b) { SET_VAR(rareInheritedData, m_subtreeWillChangeContents, b); } + + bool requiresAcceleratedCompositingForExternalReasons(bool b) { return rareNonInheritedData->m_requiresAcceleratedCompositingForExternalReasons; } + void setRequiresAcceleratedCompositingForExternalReasons(bool b) { SET_VAR(rareNonInheritedData, m_requiresAcceleratedCompositingForExternalReasons, b); } + const SVGRenderStyle* svgStyle() const { return m_svgStyle.get(); } SVGRenderStyle* accessSVGStyle() { return m_svgStyle.access(); } @@ -1375,12 +1417,12 @@ public: 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); } - SVGLength strokeWidth() const { return svgStyle()->strokeWidth(); } - void setStrokeWidth(SVGLength w) { accessSVGStyle()->setStrokeWidth(w); } - Vector<SVGLength> strokeDashArray() const { return svgStyle()->strokeDashArray(); } - void setStrokeDashArray(Vector<SVGLength> array) { accessSVGStyle()->setStrokeDashArray(array); } - SVGLength strokeDashOffset() const { return svgStyle()->strokeDashOffset(); } - void setStrokeDashOffset(SVGLength d) { accessSVGStyle()->setStrokeDashOffset(d); } + SVGLength* strokeWidth() const { return svgStyle()->strokeWidth(); } + void setStrokeWidth(PassRefPtr<SVGLength> w) { accessSVGStyle()->setStrokeWidth(w); } + SVGLengthList* strokeDashArray() const { return svgStyle()->strokeDashArray(); } + void setStrokeDashArray(PassRefPtr<SVGLengthList> array) { accessSVGStyle()->setStrokeDashArray(array); } + SVGLength* strokeDashOffset() const { return svgStyle()->strokeDashOffset(); } + void setStrokeDashOffset(PassRefPtr<SVGLength> d) { accessSVGStyle()->setStrokeDashOffset(d); } float strokeMiterLimit() const { return svgStyle()->strokeMiterLimit(); } void setStrokeMiterLimit(float f) { accessSVGStyle()->setStrokeMiterLimit(f); } @@ -1394,25 +1436,8 @@ public: void setFloodColor(const Color& c) { accessSVGStyle()->setFloodColor(c); } void setLightingColor(const Color& c) { accessSVGStyle()->setLightingColor(c); } - SVGLength baselineShiftValue() const { return svgStyle()->baselineShiftValue(); } - void setBaselineShiftValue(SVGLength s) { accessSVGStyle()->setBaselineShiftValue(s); } - SVGLength kerning() const { return svgStyle()->kerning(); } - void setKerning(SVGLength k) { accessSVGStyle()->setKerning(k); } - - void setShapeInside(PassRefPtr<ShapeValue> value) - { - if (rareNonInheritedData->m_shapeInside == value) - return; - rareNonInheritedData.access()->m_shapeInside = value; - } - ShapeValue* shapeInside() const { return rareNonInheritedData->m_shapeInside.get(); } - ShapeValue* resolvedShapeInside() const - { - ShapeValue* shapeInside = this->shapeInside(); - if (shapeInside && shapeInside->type() == ShapeValue::Outside) - return shapeOutside(); - return shapeInside; - } + SVGLength* baselineShiftValue() const { return svgStyle()->baselineShiftValue(); } + void setBaselineShiftValue(PassRefPtr<SVGLength> s) { accessSVGStyle()->setBaselineShiftValue(s); } void setShapeOutside(PassRefPtr<ShapeValue> value) { @@ -1422,7 +1447,6 @@ public: } ShapeValue* shapeOutside() const { return rareNonInheritedData->m_shapeOutside.get(); } - static ShapeValue* initialShapeInside() { return 0; } static ShapeValue* initialShapeOutside() { return 0; } void setClipPath(PassRefPtr<ClipPathOperation> operation) @@ -1434,12 +1458,8 @@ public: static ClipPathOperation* initialClipPath() { return 0; } - Length shapePadding() const { return rareNonInheritedData->m_shapePadding; } - void setShapePadding(Length shapePadding) { SET_VAR(rareNonInheritedData, m_shapePadding, shapePadding); } - static Length initialShapePadding() { return Length(0, Fixed); } - - Length shapeMargin() const { return rareNonInheritedData->m_shapeMargin; } - void setShapeMargin(Length shapeMargin) { SET_VAR(rareNonInheritedData, m_shapeMargin, shapeMargin); } + const Length& shapeMargin() const { return rareNonInheritedData->m_shapeMargin; } + void setShapeMargin(const Length& shapeMargin) { SET_VAR(rareNonInheritedData, m_shapeMargin, shapeMargin); } static Length initialShapeMargin() { return Length(0, Fixed); } float shapeImageThreshold() const { return rareNonInheritedData->m_shapeImageThreshold; } @@ -1471,17 +1491,9 @@ public: bool inheritedNotEqual(const RenderStyle*) const; bool inheritedDataShared(const RenderStyle*) const; - 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 isDisplayRegionType() const - { - return display() == BLOCK || display() == INLINE_BLOCK - || display() == TABLE_CELL || display() == TABLE_CAPTION - || display() == LIST_ITEM; - } bool setWritingMode(WritingMode v) { @@ -1505,6 +1517,8 @@ public: bool lastChildState() const { return noninherited_flags.lastChildState; } void setLastChildState() { setUnique(); noninherited_flags.lastChildState = true; } + StyleColor visitedDependentDecorationStyleColor() const; + Color visitedDependentDecorationColor() const; Color visitedDependentColor(int colorProperty) const; void setHasExplicitlyInheritedProperties() { noninherited_flags.explicitInheritance = true; } @@ -1521,8 +1535,6 @@ public: static LengthSize initialBorderRadius() { return LengthSize(Length(0, Fixed), Length(0, Fixed)); } static ECaptionSide initialCaptionSide() { return CAPTOP; } static EClear initialClear() { return CNONE; } - static ColumnAxis initialColumnAxis() { return AutoColumnAxis; } - static ColumnProgression initialColumnProgression() { return NormalColumnProgression; } static TextDirection initialDirection() { return LTR; } static WritingMode initialWritingMode() { return TopToBottomWritingMode; } static TextCombine initialTextCombine() { return TextCombineNone; } @@ -1560,6 +1572,7 @@ public: static Length initialPadding() { return Length(Fixed); } static Length initialTextIndent() { return Length(Fixed); } static TextIndentLine initialTextIndentLine() { return TextIndentFirstLine; } + static TextIndentType initialTextIndentType() { return TextIndentNormal; } static EVerticalAlign initialVerticalAlign() { return BASELINE; } static short initialWidows() { return 2; } static short initialOrphans() { return 2; } @@ -1580,8 +1593,8 @@ public: static EBoxOrient initialBoxOrient() { return HORIZONTAL; } static EBoxPack initialBoxPack() { return Start; } static float initialBoxFlex() { return 0.0f; } - static unsigned int initialBoxFlexGroup() { return 1; } - static unsigned int initialBoxOrdinalGroup() { return 1; } + static unsigned initialBoxFlexGroup() { return 1; } + static unsigned initialBoxOrdinalGroup() { return 1; } static EBoxSizing initialBoxSizing() { return CONTENT_BOX; } static StyleReflection* initialBoxReflect() { return 0; } static float initialFlexGrow() { return 0; } @@ -1589,11 +1602,15 @@ public: static Length initialFlexBasis() { return Length(Auto); } static int initialOrder() { return 0; } static EAlignContent initialAlignContent() { return AlignContentStretch; } - static EAlignItems initialAlignItems() { return AlignStretch; } - static EAlignItems initialAlignSelf() { return AlignAuto; } + static ItemPosition initialAlignItems() { return ItemPositionStretch; } + static OverflowAlignment initialAlignItemsOverflowAlignment() { return OverflowAlignmentDefault; } + static ItemPosition initialAlignSelf() { return ItemPositionAuto; } + static OverflowAlignment initialAlignSelfOverflowAlignment() { return OverflowAlignmentDefault; } static EFlexDirection initialFlexDirection() { return FlowRow; } static EFlexWrap initialFlexWrap() { return FlexNoWrap; } static EJustifyContent initialJustifyContent() { return JustifyFlexStart; } + static ItemPosition initialJustifySelf() { return ItemPositionAuto; } + static OverflowAlignment initialJustifySelfOverflowAlignment() { return OverflowAlignmentDefault; } static int initialMarqueeLoopCount() { return -1; } static int initialMarqueeSpeed() { return 85; } static Length initialMarqueeIncrement() { return Length(6, Fixed); } @@ -1653,15 +1670,16 @@ public: static TouchActionDelay initialTouchActionDelay() { return TouchActionDelayScript; } static ShadowList* initialBoxShadow() { return 0; } static ShadowList* initialTextShadow() { return 0; } + static ScrollBehavior initialScrollBehavior() { return ScrollBehaviorInstant; } // The initial value is 'none' for grid tracks. - static Vector<GridTrackSize> initialGridDefinitionColumns() { return Vector<GridTrackSize>(); } - static Vector<GridTrackSize> initialGridDefinitionRows() { return Vector<GridTrackSize>(); } + static Vector<GridTrackSize> initialGridTemplateColumns() { return Vector<GridTrackSize>(); } + static Vector<GridTrackSize> initialGridTemplateRows() { return Vector<GridTrackSize>(); } static GridAutoFlow initialGridAutoFlow() { return AutoFlowNone; } - static GridTrackSize initialGridAutoColumns() { return GridTrackSize(Auto); } - static GridTrackSize initialGridAutoRows() { return GridTrackSize(Auto); } + static GridTrackSize initialGridAutoColumns() { return GridTrackSize(Length(Auto)); } + static GridTrackSize initialGridAutoRows() { return GridTrackSize(Length(Auto)); } static NamedGridLinesMap initialNamedGridColumnLines() { return NamedGridLinesMap(); } static NamedGridLinesMap initialNamedGridRowLines() { return NamedGridLinesMap(); } @@ -1680,14 +1698,6 @@ public: static unsigned initialTabSize() { return 8; } - static const AtomicString& initialLineGrid() { return nullAtom; } - static LineSnap initialLineSnap() { return LineSnapNone; } - static LineAlign initialLineAlign() { return LineAlignNone; } - - static const AtomicString& initialFlowThread() { return nullAtom; } - static const AtomicString& initialRegionThread() { return nullAtom; } - static RegionFragment initialRegionFragment() { return AutoRegionFragment; } - static WrapFlow initialWrapFlow() { return WrapFlowAuto; } static WrapThrough initialWrapThrough() { return WrapThroughWrap; } @@ -1703,17 +1713,17 @@ public: static EIsolation initialIsolation() { return IsolationAuto; } private: void setVisitedLinkColor(const Color&); - void setVisitedLinkBackgroundColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBackgroundColor, v); } - void setVisitedLinkBorderLeftColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBorderLeftColor, v); } - void setVisitedLinkBorderRightColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBorderRightColor, v); } - void setVisitedLinkBorderBottomColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBorderBottomColor, v); } - void setVisitedLinkBorderTopColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBorderTopColor, v); } - void setVisitedLinkOutlineColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkOutlineColor, v); } - void setVisitedLinkColumnRuleColor(const Color& v) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_visitedLinkColumnRuleColor, v); } - void setVisitedLinkTextDecorationColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkTextDecorationColor, v); } - void setVisitedLinkTextEmphasisColor(const Color& v) { SET_VAR(rareInheritedData, visitedLinkTextEmphasisColor, v); } - void setVisitedLinkTextFillColor(const Color& v) { SET_VAR(rareInheritedData, visitedLinkTextFillColor, v); } - void setVisitedLinkTextStrokeColor(const Color& v) { SET_VAR(rareInheritedData, visitedLinkTextStrokeColor, v); } + void setVisitedLinkBackgroundColor(const StyleColor& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBackgroundColor, v); } + void setVisitedLinkBorderLeftColor(const StyleColor& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBorderLeftColor, v); } + void setVisitedLinkBorderRightColor(const StyleColor& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBorderRightColor, v); } + void setVisitedLinkBorderBottomColor(const StyleColor& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBorderBottomColor, v); } + void setVisitedLinkBorderTopColor(const StyleColor& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBorderTopColor, v); } + void setVisitedLinkOutlineColor(const StyleColor& v) { SET_VAR(rareNonInheritedData, m_visitedLinkOutlineColor, v); } + void setVisitedLinkColumnRuleColor(const StyleColor& v) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_visitedLinkColumnRuleColor, v); } + void setVisitedLinkTextDecorationColor(const StyleColor& v) { SET_VAR(rareNonInheritedData, m_visitedLinkTextDecorationColor, v); } + void setVisitedLinkTextEmphasisColor(const StyleColor& v) { SET_VAR_WITH_SETTER(rareInheritedData, visitedLinkTextEmphasisColor, setVisitedLinkTextEmphasisColor, v); } + void setVisitedLinkTextFillColor(const StyleColor& v) { SET_VAR_WITH_SETTER(rareInheritedData, visitedLinkTextFillColor, setVisitedLinkTextFillColor, v); } + void setVisitedLinkTextStrokeColor(const StyleColor& v) { SET_VAR_WITH_SETTER(rareInheritedData, visitedLinkTextStrokeColor, setVisitedLinkTextStrokeColor, v); } void inheritUnicodeBidiFrom(const RenderStyle* parent) { noninherited_flags._unicodeBidi = parent->noninherited_flags._unicodeBidi; } void getShadowExtent(const ShadowList*, LayoutUnit& top, LayoutUnit& right, LayoutUnit& bottom, LayoutUnit& left) const; @@ -1741,31 +1751,30 @@ private: } // Color accessors are all private to make sure callers use visitedDependentColor instead to access them. - 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(); } + StyleColor borderLeftColor() const { return surround->border.left().color(); } + StyleColor borderRightColor() const { return surround->border.right().color(); } + StyleColor borderTopColor() const { return surround->border.top().color(); } + StyleColor borderBottomColor() const { return surround->border.bottom().color(); } + StyleColor backgroundColor() const { return m_background->color(); } Color color() const; - 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; } + StyleColor columnRuleColor() const { return rareNonInheritedData->m_multiCol->m_rule.color(); } + StyleColor outlineColor() const { return m_background->outline().color(); } + StyleColor textEmphasisColor() const { return rareInheritedData->textEmphasisColor(); } + StyleColor textFillColor() const { return rareInheritedData->textFillColor(); } + StyleColor textStrokeColor() const { return rareInheritedData->textStrokeColor(); } Color visitedLinkColor() const; - 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 textDecorationColor() const { return rareNonInheritedData->m_textDecorationColor; } - Color visitedLinkTextDecorationColor() const { return rareNonInheritedData->m_visitedLinkTextDecorationColor; } - Color visitedLinkTextEmphasisColor() const { return rareInheritedData->visitedLinkTextEmphasisColor; } - Color visitedLinkTextFillColor() const { return rareInheritedData->visitedLinkTextFillColor; } - Color visitedLinkTextStrokeColor() const { return rareInheritedData->visitedLinkTextStrokeColor; } + StyleColor visitedLinkBackgroundColor() const { return rareNonInheritedData->m_visitedLinkBackgroundColor; } + StyleColor visitedLinkBorderLeftColor() const { return rareNonInheritedData->m_visitedLinkBorderLeftColor; } + StyleColor visitedLinkBorderRightColor() const { return rareNonInheritedData->m_visitedLinkBorderRightColor; } + StyleColor visitedLinkBorderBottomColor() const { return rareNonInheritedData->m_visitedLinkBorderBottomColor; } + StyleColor visitedLinkBorderTopColor() const { return rareNonInheritedData->m_visitedLinkBorderTopColor; } + StyleColor visitedLinkOutlineColor() const { return rareNonInheritedData->m_visitedLinkOutlineColor; } + StyleColor visitedLinkColumnRuleColor() const { return rareNonInheritedData->m_multiCol->m_visitedLinkColumnRuleColor; } + StyleColor textDecorationColor() const { return rareNonInheritedData->m_textDecorationColor; } + StyleColor visitedLinkTextDecorationColor() const { return rareNonInheritedData->m_visitedLinkTextDecorationColor; } + StyleColor visitedLinkTextEmphasisColor() const { return rareInheritedData->visitedLinkTextEmphasisColor(); } + StyleColor visitedLinkTextFillColor() const { return rareInheritedData->visitedLinkTextFillColor(); } + StyleColor visitedLinkTextStrokeColor() const { return rareInheritedData->visitedLinkTextStrokeColor(); } Color colorIncludingFallback(int colorProperty, bool visitedLink) const; @@ -1774,22 +1783,32 @@ private: Color lightingColor() const { return svgStyle()->lightingColor(); } void appendContent(PassOwnPtr<ContentData>); - StyleDifference repaintOnlyDiff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const; + void addAppliedTextDecoration(const AppliedTextDecoration&); + + bool diffNeedsFullLayoutAndRepaint(const RenderStyle& other) const; + bool diffNeedsFullLayout(const RenderStyle& other) const; + bool diffNeedsRepaintLayer(const RenderStyle& other) const; + bool diffNeedsRepaintObject(const RenderStyle& other) const; + bool diffNeedsRecompositeLayer(const RenderStyle& other) const; + unsigned computeChangedContextSensitiveProperties(const RenderStyle& other, StyleDifference) const; }; +// FIXME: Reduce/remove the dependency on zoom adjusted int values. +// The float or LayoutUnit versions of layout values should be used. inline int adjustForAbsoluteZoom(int value, float zoomFactor) { if (zoomFactor == 1) return value; // Needed because computeLengthInt truncates (rather than rounds) when scaling up. + float fvalue = value; if (zoomFactor > 1) { if (value < 0) - value--; + fvalue -= 0.5f; else - value++; + fvalue += 0.5f; } - return roundForImpreciseConversion<int>(value / zoomFactor); + return roundForImpreciseConversion<int>(fvalue / zoomFactor); } inline int adjustForAbsoluteZoom(int value, const RenderStyle* style) @@ -1802,6 +1821,11 @@ inline float adjustFloatForAbsoluteZoom(float value, const RenderStyle& style) return value / style.effectiveZoom(); } +inline double adjustDoubleForAbsoluteZoom(double value, const RenderStyle& style) +{ + return value / style.effectiveZoom(); +} + inline LayoutUnit adjustLayoutUnitForAbsoluteZoom(LayoutUnit value, const RenderStyle& style) { return value / style.effectiveZoom(); @@ -1830,8 +1854,6 @@ inline bool RenderStyle::isSharable() const return false; if (hasUniquePseudoStyle()) return false; - if (transitions() || animations()) - return false; return true; } @@ -1863,6 +1885,13 @@ inline void RenderStyle::setHasPseudoStyle(PseudoId pseudo) noninherited_flags._pseudoBits |= 1 << (pseudo - 1); } +inline bool RenderStyle::hasPseudoElementStyle() const +{ + return noninherited_flags._pseudoBits & PSEUDO_ELEMENT_MASK; +} + +float calcBorderRadiiConstraintScaleFor(const FloatRect&, const FloatRoundedRect::Radii&); + } // namespace WebCore #endif // RenderStyle_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/RenderStyleConstants.h b/chromium/third_party/WebKit/Source/core/rendering/style/RenderStyleConstants.h index 45531d20231..f2a3d006af0 100755..100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/RenderStyleConstants.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/RenderStyleConstants.h @@ -31,9 +31,11 @@ namespace WebCore { enum StyleRecalcChange { NoChange, NoInherit, + UpdatePseudoElements, Inherit, Force, Reattach, + ReattachNoRenderer }; static const size_t PrintColorAdjustBits = 1; @@ -42,37 +44,18 @@ enum PrintColorAdjust { PrintColorAdjustExact }; -// The difference between two styles. The following values are used: -// (1) StyleDifferenceEqual - The two styles are identical. -// (2) StyleDifferenceRecompositeLayer - The layer needs its position and transform updated, but no repaint. -// (3) StyleDifferenceRepaint - The object just needs to be repainted. -// (4) StyleDifferenceRepaintIfTextOrColorChange - The object needs to be repainted if it contains text or properties dependent on color (e.g., border or outline). -// (5) StyleDifferenceRepaintLayer - The layer and its descendant layers needs to be repainted. -// (6) StyleDifferenceLayoutPositionedMovementOnly - Only the position of this positioned object has been updated. -// (7) StyleDifferenceSimplifiedLayout - Only overflow needs to be recomputed. -// (8) StyleDifferenceSimplifiedLayoutAndPositionedMovement - Both positioned movement and simplified layout updates are required. -// (9) StyleDifferenceLayout - A full layout is required. -enum StyleDifference { - StyleDifferenceEqual, - StyleDifferenceRecompositeLayer, - StyleDifferenceRepaint, - StyleDifferenceRepaintIfTextOrColorChange, - StyleDifferenceRepaintLayer, - StyleDifferenceLayoutPositionedMovementOnly, - StyleDifferenceSimplifiedLayout, - StyleDifferenceSimplifiedLayoutAndPositionedMovement, - StyleDifferenceLayout -}; - // When some style properties change, different amounts of work have to be done depending on // context (e.g. whether the property is changing on an element which has a compositing layer). // A simple StyleDifference does not provide enough information so we return a bit mask of -// StyleDifferenceContextSensitiveProperties from RenderStyle::diff() too. +// StyleDifferenceContextSensitiveProperties from RenderStyle::visualInvalidationDiff() too. enum StyleDifferenceContextSensitiveProperty { ContextSensitivePropertyNone = 0, ContextSensitivePropertyTransform = (1 << 0), ContextSensitivePropertyOpacity = (1 << 1), - ContextSensitivePropertyFilter = (1 << 2) + ContextSensitivePropertyZIndex = (1 << 2), + ContextSensitivePropertyFilter = (1 << 3), + // The object needs to be repainted if it contains text or properties dependent on color (e.g., border or outline). + ContextSensitivePropertyTextOrColor = (1 << 4) }; // Static pseudo styles. Dynamic ones are produced on the fly. @@ -81,13 +64,13 @@ enum PseudoId { // If you add or remove a public ID, you must update _pseudoBits in RenderStyle. NOPSEUDO, FIRST_LINE, FIRST_LETTER, BEFORE, AFTER, BACKDROP, SELECTION, FIRST_LINE_INHERITED, SCROLLBAR, // Internal IDs follow: - SCROLLBAR_THUMB, SCROLLBAR_BUTTON, SCROLLBAR_TRACK, SCROLLBAR_TRACK_PIECE, SCROLLBAR_CORNER, RESIZER, - INPUT_LIST_BUTTON, + SCROLLBAR_THUMB, SCROLLBAR_BUTTON, SCROLLBAR_TRACK, SCROLLBAR_TRACK_PIECE, SCROLLBAR_CORNER, RESIZER, INPUT_LIST_BUTTON, + // Special values follow: AFTER_LAST_INTERNAL_PSEUDOID, - FULL_SCREEN, FULL_SCREEN_DOCUMENT, FULL_SCREEN_ANCESTOR, FIRST_PUBLIC_PSEUDOID = FIRST_LINE, FIRST_INTERNAL_PSEUDOID = SCROLLBAR_THUMB, - PUBLIC_PSEUDOID_MASK = ((1 << FIRST_INTERNAL_PSEUDOID) - 1) & ~((1 << FIRST_PUBLIC_PSEUDOID) - 1) + PUBLIC_PSEUDOID_MASK = ((1 << FIRST_INTERNAL_PSEUDOID) - 1) & ~((1 << FIRST_PUBLIC_PSEUDOID) - 1), + PSEUDO_ELEMENT_MASK = (1 << (BEFORE - 1)) | (1 << (AFTER - 1)) | (1 << (BACKDROP - 1)) }; enum ColumnFill { ColumnFillBalance, ColumnFillAuto }; @@ -191,7 +174,6 @@ enum EBoxDirection { BNORMAL, BREVERSE }; // CSS3 Flexbox Properties enum EAlignContent { AlignContentFlexStart, AlignContentFlexEnd, AlignContentCenter, AlignContentSpaceBetween, AlignContentSpaceAround, AlignContentStretch }; -enum EAlignItems { AlignAuto, AlignFlexStart, AlignFlexEnd, AlignCenter, AlignStretch, AlignBaseline }; enum EFlexDirection { FlowRow, FlowRowReverse, FlowColumn, FlowColumnReverse }; enum EFlexWrap { FlexNoWrap, FlexWrap, FlexWrapReverse }; enum EJustifyContent { JustifyFlexStart, JustifyFlexEnd, JustifyCenter, JustifySpaceBetween, JustifySpaceAround }; @@ -330,11 +312,9 @@ enum QuoteType { enum EBorderFit { BorderFitBorder, BorderFitLines }; -enum EAnimationFillMode { AnimationFillModeNone, AnimationFillModeForwards, AnimationFillModeBackwards, AnimationFillModeBoth }; - enum EAnimPlayState { - AnimPlayStatePlaying = 0x0, - AnimPlayStatePaused = 0x1 + AnimPlayStatePlaying, + AnimPlayStatePaused }; enum EWhiteSpace { @@ -413,8 +393,8 @@ enum ECursor { CURSOR_PROGRESS, CURSOR_NO_DROP, CURSOR_NOT_ALLOWED, - CURSOR_WEBKIT_ZOOM_IN, - CURSOR_WEBKIT_ZOOM_OUT, + CURSOR_ZOOM_IN, + CURSOR_ZOOM_OUT, CURSOR_E_RESIZE, CURSOR_NE_RESIZE, CURSOR_NW_RESIZE, @@ -450,7 +430,9 @@ enum EDisplay { TABLE_CAPTION, BOX, INLINE_BOX, FLEX, INLINE_FLEX, GRID, INLINE_GRID, - NONE + NONE, + FIRST_TABLE_DISPLAY = TABLE, + LAST_TABLE_DISPLAY = TABLE_CAPTION }; enum EInsideLink { @@ -495,16 +477,6 @@ enum ImageResolutionSnap { ImageResolutionNoSnap = 0, ImageResolutionSnapPixels enum Order { LogicalOrder = 0, VisualOrder }; -enum RegionFragment { AutoRegionFragment, BreakRegionFragment }; - -enum ColumnAxis { HorizontalColumnAxis, VerticalColumnAxis, AutoColumnAxis }; - -enum ColumnProgression { NormalColumnProgression, ReverseColumnProgression }; - -enum LineSnap { LineSnapNone, LineSnapBaseline, LineSnapContain }; - -enum LineAlign { LineAlignNone, LineAlignEdges }; - enum WrapFlow { WrapFlowAuto, WrapFlowBoth, WrapFlowStart, WrapFlowEnd, WrapFlowMaximum, WrapFlowClear }; enum WrapThrough { WrapThroughWrap, WrapThroughNone }; @@ -515,12 +487,13 @@ enum GridAutoFlow { AutoFlowNone, AutoFlowColumn, AutoFlowRow }; enum DraggableRegionMode { DraggableRegionNone, DraggableRegionDrag, DraggableRegionNoDrag }; -static const size_t TouchActionBits = 3; +static const size_t TouchActionBits = 4; enum TouchAction { TouchActionAuto = 0x0, TouchActionNone = 0x1, TouchActionPanX = 0x2, - TouchActionPanY = 0x4 + TouchActionPanY = 0x4, + TouchActionPinchZoom = 0x8, }; inline TouchAction operator| (TouchAction a, TouchAction b) { return TouchAction(int(a) | int(b)); } inline TouchAction& operator|= (TouchAction& a, TouchAction b) { return a = a | b; } @@ -531,12 +504,34 @@ enum EIsolation { IsolationAuto, IsolationIsolate }; enum TouchActionDelay { TouchActionDelayNone, TouchActionDelayScript }; +enum ItemPosition { + ItemPositionAuto, + ItemPositionStretch, + ItemPositionBaseline, + ItemPositionCenter, + ItemPositionStart, + ItemPositionEnd, + ItemPositionSelfStart, + ItemPositionSelfEnd, + ItemPositionFlexStart, + ItemPositionFlexEnd, + ItemPositionLeft, + ItemPositionRight +}; + +enum OverflowAlignment { + OverflowAlignmentDefault, + OverflowAlignmentTrue, + OverflowAlignmentSafe +}; + // Reasonable maximum to prevent insane font sizes from causing crashes on some platforms (such as Windows). static const float maximumAllowedFontSize = 1000000.0f; enum TextIndentLine { TextIndentFirstLine, TextIndentEachLine }; +enum TextIndentType { TextIndentNormal, TextIndentHanging }; -enum LayoutBox { MarginBox, BorderBox, PaddingBox, ContentBox }; +enum CSSBoxType { BoxMissing = 0, MarginBox, BorderBox, PaddingBox, ContentBox }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/SVGRenderStyle.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/SVGRenderStyle.cpp index 947c39db641..2e0646ed587 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/SVGRenderStyle.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/SVGRenderStyle.cpp @@ -40,7 +40,6 @@ SVGRenderStyle::SVGRenderStyle() fill = defaultStyle->fill; stroke = defaultStyle->stroke; - text = defaultStyle->text; stops = defaultStyle->stops; misc = defaultStyle->misc; inheritedResources = defaultStyle->inheritedResources; @@ -55,7 +54,6 @@ SVGRenderStyle::SVGRenderStyle(CreateDefaultType) fill.init(); stroke.init(); - text.init(); stops.init(); misc.init(); inheritedResources.init(); @@ -67,7 +65,6 @@ SVGRenderStyle::SVGRenderStyle(const SVGRenderStyle& other) { fill = other.fill; stroke = other.stroke; - text = other.text; stops = other.stops; misc = other.misc; inheritedResources = other.inheritedResources; @@ -85,7 +82,6 @@ bool SVGRenderStyle::operator==(const SVGRenderStyle& other) const { return fill == other.fill && stroke == other.stroke - && text == other.text && stops == other.stops && misc == other.misc && inheritedResources == other.inheritedResources @@ -98,7 +94,6 @@ bool SVGRenderStyle::inheritedNotEqual(const SVGRenderStyle* other) const { return fill != other->fill || stroke != other->stroke - || text != other->text || inheritedResources != other->inheritedResources || svg_inherited_flags != other->svg_inherited_flags; } @@ -110,7 +105,6 @@ void SVGRenderStyle::inheritFrom(const SVGRenderStyle* svgInheritParent) fill = svgInheritParent->fill; stroke = svgInheritParent->stroke; - text = svgInheritParent->text; inheritedResources = svgInheritParent->inheritedResources; svg_inherited_flags = svgInheritParent->svg_inherited_flags; @@ -126,19 +120,27 @@ void SVGRenderStyle::copyNonInheritedFrom(const SVGRenderStyle* other) StyleDifference SVGRenderStyle::diff(const SVGRenderStyle* other) const { - // NOTE: All comparisions that may return StyleDifferenceLayout have to go before those who return StyleDifferenceRepaint + StyleDifference styleDifference; - // If kerning changes, we need a relayout, to force SVGCharacterData to be recalculated in the SVGRootInlineBox. - if (text != other->text) - return StyleDifferenceLayout; + if (diffNeedsLayoutAndRepaint(other)) { + styleDifference.setNeedsFullLayout(); + styleDifference.setNeedsRepaintObject(); + } else if (diffNeedsRepaint(other)) { + styleDifference.setNeedsRepaintObject(); + } + + return styleDifference; +} +bool SVGRenderStyle::diffNeedsLayoutAndRepaint(const SVGRenderStyle* other) const +{ // If resources change, we need a relayout, as the presence of resources influences the repaint rect. if (resources != other->resources) - return StyleDifferenceLayout; + return true; // If markers change, we need a relayout, as marker boundaries are cached in RenderSVGPath. if (inheritedResources != other->inheritedResources) - return StyleDifferenceLayout; + return true; // All text related properties influence layout. if (svg_inherited_flags._textAnchor != other->svg_inherited_flags._textAnchor @@ -148,20 +150,23 @@ StyleDifference SVGRenderStyle::diff(const SVGRenderStyle* other) const || svg_noninherited_flags.f._alignmentBaseline != other->svg_noninherited_flags.f._alignmentBaseline || svg_noninherited_flags.f._dominantBaseline != other->svg_noninherited_flags.f._dominantBaseline || svg_noninherited_flags.f._baselineShift != other->svg_noninherited_flags.f._baselineShift) - return StyleDifferenceLayout; + return true; // Text related properties influence layout. - bool miscNotEqual = misc != other->misc; - if (miscNotEqual && misc->baselineShiftValue != other->misc->baselineShiftValue) - return StyleDifferenceLayout; + if (misc->baselineShiftValue != other->misc->baselineShiftValue) + return true; // These properties affect the cached stroke bounding box rects. if (svg_inherited_flags._capStyle != other->svg_inherited_flags._capStyle || svg_inherited_flags._joinStyle != other->svg_inherited_flags._joinStyle) - return StyleDifferenceLayout; + return true; + + // vector-effect changes require a re-layout. + if (svg_noninherited_flags.f._vectorEffect != other->svg_noninherited_flags.f._vectorEffect) + return true; // Some stroke properties, requires relayouts, as the cached stroke boundaries need to be recalculated. - if (stroke != other->stroke) { + if (stroke.get() != other->stroke.get()) { if (stroke->width != other->stroke->width || stroke->paintType != other->stroke->paintType || stroke->paintColor != other->stroke->paintColor @@ -172,35 +177,37 @@ StyleDifference SVGRenderStyle::diff(const SVGRenderStyle* other) const || stroke->visitedLinkPaintColor != other->stroke->visitedLinkPaintColor || stroke->visitedLinkPaintUri != other->stroke->visitedLinkPaintUri || stroke->visitedLinkPaintType != other->stroke->visitedLinkPaintType) - return StyleDifferenceLayout; - - // Only the stroke-opacity case remains, where we only need a repaint. - ASSERT(stroke->opacity != other->stroke->opacity); - return StyleDifferenceRepaint; + return true; } - // vector-effect changes require a re-layout. - if (svg_noninherited_flags.f._vectorEffect != other->svg_noninherited_flags.f._vectorEffect) - return StyleDifferenceLayout; + return false; +} - // NOTE: All comparisions below may only return StyleDifferenceRepaint +bool SVGRenderStyle::diffNeedsRepaint(const SVGRenderStyle* other) const +{ + if (stroke->opacity != other->stroke->opacity) + return true; // Painting related properties only need repaints. - if (miscNotEqual) { + if (misc.get() != other->misc.get()) { if (misc->floodColor != other->misc->floodColor || misc->floodOpacity != other->misc->floodOpacity || misc->lightingColor != other->misc->lightingColor) - return StyleDifferenceRepaint; + return true; } // If fill changes, we just need to repaint. Fill boundaries are not influenced by this, only by the Path, that RenderSVGPath contains. - if (fill->paintType != other->fill->paintType || fill->paintColor != other->fill->paintColor - || fill->paintUri != other->fill->paintUri || fill->opacity != other->fill->opacity) - return StyleDifferenceRepaint; + if (fill.get() != other->fill.get()) { + if (fill->paintType != other->fill->paintType + || fill->paintColor != other->fill->paintColor + || fill->paintUri != other->fill->paintUri + || fill->opacity != other->fill->opacity) + return true; + } // If gradient stops change, we just need to repaint. Style updates are already handled through RenderSVGGradientSTop. if (stops != other->stops) - return StyleDifferenceRepaint; + return true; // Changes of these flags only cause repaints. if (svg_inherited_flags._colorRendering != other->svg_inherited_flags._colorRendering @@ -210,15 +217,15 @@ StyleDifference SVGRenderStyle::diff(const SVGRenderStyle* other) const || svg_inherited_flags._colorInterpolation != other->svg_inherited_flags._colorInterpolation || svg_inherited_flags._colorInterpolationFilters != other->svg_inherited_flags._colorInterpolationFilters || svg_inherited_flags._paintOrder != other->svg_inherited_flags._paintOrder) - return StyleDifferenceRepaint; + return true; if (svg_noninherited_flags.f.bufferedRendering != other->svg_noninherited_flags.f.bufferedRendering) - return StyleDifferenceRepaint; + return true; if (svg_noninherited_flags.f.maskType != other->svg_noninherited_flags.f.maskType) - return StyleDifferenceRepaint; + return true; - return StyleDifferenceEqual; + return false; } EPaintOrderType SVGRenderStyle::paintOrderType(unsigned index) const diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/SVGRenderStyle.h b/chromium/third_party/WebKit/Source/core/rendering/style/SVGRenderStyle.h index dba333e1ddf..128ed626aa7 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/SVGRenderStyle.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/SVGRenderStyle.h @@ -28,16 +28,13 @@ #include "core/rendering/style/DataRef.h" #include "core/rendering/style/RenderStyleConstants.h" #include "core/rendering/style/SVGRenderStyleDefs.h" +#include "core/rendering/style/StyleDifference.h" #include "core/svg/SVGPaint.h" #include "platform/graphics/GraphicsTypes.h" #include "platform/graphics/Path.h" namespace WebCore { -class FloatRect; -class IntRect; -class RenderObject; - class SVGRenderStyle : public RefCounted<SVGRenderStyle> { public: static PassRefPtr<SVGRenderStyle> create() { return adoptRef(new SVGRenderStyle); } @@ -79,48 +76,41 @@ public: static SVGPaint::SVGPaintType initialStrokePaintType() { return SVGPaint::SVG_PAINTTYPE_NONE; } static Color initialStrokePaintColor() { return Color(); } static String initialStrokePaintUri() { return String(); } - static Vector<SVGLength> initialStrokeDashArray() { return Vector<SVGLength>(); } + static PassRefPtr<SVGLengthList> initialStrokeDashArray() { return SVGLengthList::create(); } static float initialStrokeMiterLimit() { return 4; } static float initialStopOpacity() { return 1; } static Color initialStopColor() { return Color(0, 0, 0); } static float initialFloodOpacity() { return 1; } static Color initialFloodColor() { return Color(0, 0, 0); } static Color initialLightingColor() { return Color(255, 255, 255); } - static String initialClipperResource() { return String(); } - static String initialFilterResource() { return String(); } - static String initialMaskerResource() { return String(); } - static String initialMarkerStartResource() { return String(); } - static String initialMarkerMidResource() { return String(); } - static String initialMarkerEndResource() { return String(); } + static const AtomicString& initialClipperResource() { return nullAtom; } + static const AtomicString& initialFilterResource() { return nullAtom; } + static const AtomicString& initialMaskerResource() { return nullAtom; } + static const AtomicString& initialMarkerStartResource() { return nullAtom; } + static const AtomicString& initialMarkerMidResource() { return nullAtom; } + static const AtomicString& initialMarkerEndResource() { return nullAtom; } static EMaskType initialMaskType() { return MT_LUMINANCE; } static EPaintOrder initialPaintOrder() { return PO_NORMAL; } - static SVGLength initialBaselineShiftValue() - { - SVGLength length; - length.newValueSpecifiedUnits(LengthTypeNumber, 0, ASSERT_NO_EXCEPTION); - return length; - } - - static SVGLength initialKerning() + static PassRefPtr<SVGLength> initialBaselineShiftValue() { - SVGLength length; - length.newValueSpecifiedUnits(LengthTypeNumber, 0, ASSERT_NO_EXCEPTION); - return length; + RefPtr<SVGLength> length = SVGLength::create(); + length->newValueSpecifiedUnits(LengthTypeNumber, 0); + return length.release(); } - static SVGLength initialStrokeDashOffset() + static PassRefPtr<SVGLength> initialStrokeDashOffset() { - SVGLength length; - length.newValueSpecifiedUnits(LengthTypeNumber, 0, ASSERT_NO_EXCEPTION); - return length; + RefPtr<SVGLength> length = SVGLength::create(); + length->newValueSpecifiedUnits(LengthTypeNumber, 0); + return length.release(); } - static SVGLength initialStrokeWidth() + static PassRefPtr<SVGLength> initialStrokeWidth() { - SVGLength length; - length.newValueSpecifiedUnits(LengthTypeNumber, 1, ASSERT_NO_EXCEPTION); - return length; + RefPtr<SVGLength> length = SVGLength::create(); + length->newValueSpecifiedUnits(LengthTypeNumber, 1); + return length.release(); } // SVG CSS Property setters @@ -196,7 +186,7 @@ public: } } - void setStrokeDashArray(const Vector<SVGLength>& obj) + void setStrokeDashArray(PassRefPtr<SVGLengthList> obj) { if (!(stroke->dashArray == obj)) stroke.access()->dashArray = obj; @@ -208,24 +198,18 @@ public: stroke.access()->miterLimit = obj; } - void setStrokeWidth(const SVGLength& obj) + void setStrokeWidth(PassRefPtr<SVGLength> obj) { if (!(stroke->width == obj)) stroke.access()->width = obj; } - void setStrokeDashOffset(const SVGLength& obj) + void setStrokeDashOffset(PassRefPtr<SVGLength> obj) { if (!(stroke->dashOffset == obj)) stroke.access()->dashOffset = obj; } - void setKerning(const SVGLength& obj) - { - if (!(text->kerning == obj)) - text.access()->kerning = obj; - } - void setStopOpacity(float obj) { if (!(stops->opacity == obj)) @@ -256,45 +240,45 @@ public: misc.access()->lightingColor = obj; } - void setBaselineShiftValue(const SVGLength& obj) + void setBaselineShiftValue(PassRefPtr<SVGLength> obj) { if (!(misc->baselineShiftValue == obj)) misc.access()->baselineShiftValue = obj; } // Setters for non-inherited resources - void setClipperResource(const String& obj) + void setClipperResource(const AtomicString& obj) { if (!(resources->clipper == obj)) resources.access()->clipper = obj; } - void setFilterResource(const String& obj) + void setFilterResource(const AtomicString& obj) { if (!(resources->filter == obj)) resources.access()->filter = obj; } - void setMaskerResource(const String& obj) + void setMaskerResource(const AtomicString& obj) { if (!(resources->masker == obj)) resources.access()->masker = obj; } // Setters for inherited resources - void setMarkerStartResource(const String& obj) + void setMarkerStartResource(const AtomicString& obj) { if (!(inheritedResources->markerStart == obj)) inheritedResources.access()->markerStart = obj; } - void setMarkerMidResource(const String& obj) + void setMarkerMidResource(const AtomicString& obj) { if (!(inheritedResources->markerMid == obj)) inheritedResources.access()->markerMid = obj; } - void setMarkerEndResource(const String& obj) + void setMarkerEndResource(const AtomicString& obj) { if (!(inheritedResources->markerEnd == obj)) inheritedResources.access()->markerEnd = obj; @@ -326,23 +310,22 @@ public: const SVGPaint::SVGPaintType& strokePaintType() const { return stroke->paintType; } const Color& strokePaintColor() const { return stroke->paintColor; } const String& strokePaintUri() const { return stroke->paintUri; } - Vector<SVGLength> strokeDashArray() const { return stroke->dashArray; } + SVGLengthList* strokeDashArray() const { return stroke->dashArray.get(); } float strokeMiterLimit() const { return stroke->miterLimit; } - SVGLength strokeWidth() const { return stroke->width; } - SVGLength strokeDashOffset() const { return stroke->dashOffset; } - SVGLength kerning() const { return text->kerning; } + SVGLength* strokeWidth() const { return stroke->width.get(); } + SVGLength* strokeDashOffset() const { return stroke->dashOffset.get(); } float stopOpacity() const { return stops->opacity; } const Color& stopColor() const { return stops->color; } float floodOpacity() const { return misc->floodOpacity; } const Color& floodColor() const { return misc->floodColor; } const Color& lightingColor() const { return misc->lightingColor; } - SVGLength baselineShiftValue() const { return misc->baselineShiftValue; } - String clipperResource() const { return resources->clipper; } - String filterResource() const { return resources->filter; } - String maskerResource() const { return resources->masker; } - String markerStartResource() const { return inheritedResources->markerStart; } - String markerMidResource() const { return inheritedResources->markerMid; } - String markerEndResource() const { return inheritedResources->markerEnd; } + SVGLength* baselineShiftValue() const { return misc->baselineShiftValue.get(); } + const AtomicString& clipperResource() const { return resources->clipper; } + const AtomicString& filterResource() const { return resources->filter; } + const AtomicString& maskerResource() const { return resources->masker; } + const AtomicString& markerStartResource() const { return inheritedResources->markerStart; } + const AtomicString& markerMidResource() const { return inheritedResources->markerMid; } + const AtomicString& markerEndResource() const { return inheritedResources->markerEnd; } EMaskType maskType() const { return (EMaskType) svg_noninherited_flags.f.maskType; } EPaintOrder paintOrder() const { return (EPaintOrder) svg_inherited_flags._paintOrder; } EPaintOrderType paintOrderType(unsigned index) const; @@ -360,7 +343,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 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; } @@ -427,7 +410,6 @@ protected: // inherited attributes DataRef<StyleFillData> fill; DataRef<StyleStrokeData> stroke; - DataRef<StyleTextData> text; DataRef<StyleInheritedResourceData> inheritedResources; // non-inherited attributes @@ -442,6 +424,9 @@ private: SVGRenderStyle(const SVGRenderStyle&); SVGRenderStyle(CreateDefaultType); // Used to create the default style. + bool diffNeedsLayoutAndRepaint(const SVGRenderStyle* other) const; + bool diffNeedsRepaint(const SVGRenderStyle* other) const; + void setBitDefaults() { svg_inherited_flags._clipRule = initialClipRule(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/SVGRenderStyleDefs.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/SVGRenderStyleDefs.cpp index 56e4a06ed5f..7a7f562b4d3 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/SVGRenderStyleDefs.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/SVGRenderStyleDefs.cpp @@ -86,9 +86,9 @@ StyleStrokeData::StyleStrokeData(const StyleStrokeData& other) : RefCounted<StyleStrokeData>() , opacity(other.opacity) , miterLimit(other.miterLimit) - , width(other.width) - , dashOffset(other.dashOffset) - , dashArray(other.dashArray) + , width(other.width->clone()) + , dashOffset(other.dashOffset->clone()) + , dashArray(other.dashArray->clone()) , paintType(other.paintType) , paintColor(other.paintColor) , paintUri(other.paintUri) @@ -100,11 +100,11 @@ StyleStrokeData::StyleStrokeData(const StyleStrokeData& other) bool StyleStrokeData::operator==(const StyleStrokeData& other) const { - return width == other.width + return *width == *other.width && opacity == other.opacity && miterLimit == other.miterLimit - && dashOffset == other.dashOffset - && dashArray == other.dashArray + && *dashOffset == *other.dashOffset + && *dashArray == *other.dashArray && paintType == other.paintType && paintColor == other.paintColor && paintUri == other.paintUri @@ -132,22 +132,6 @@ bool StyleStopData::operator==(const StyleStopData& other) const && opacity == other.opacity; } -StyleTextData::StyleTextData() - : kerning(SVGRenderStyle::initialKerning()) -{ -} - -StyleTextData::StyleTextData(const StyleTextData& other) - : RefCounted<StyleTextData>() - , kerning(other.kerning) -{ -} - -bool StyleTextData::operator==(const StyleTextData& other) const -{ - return kerning == other.kerning; -} - StyleMiscData::StyleMiscData() : floodColor(SVGRenderStyle::initialFloodColor()) , floodOpacity(SVGRenderStyle::initialFloodOpacity()) @@ -161,7 +145,7 @@ StyleMiscData::StyleMiscData(const StyleMiscData& other) , floodColor(other.floodColor) , floodOpacity(other.floodOpacity) , lightingColor(other.lightingColor) - , baselineShiftValue(other.baselineShiftValue) + , baselineShiftValue(other.baselineShiftValue->clone()) { } @@ -170,7 +154,7 @@ bool StyleMiscData::operator==(const StyleMiscData& other) const return floodOpacity == other.floodOpacity && floodColor == other.floodColor && lightingColor == other.lightingColor - && baselineShiftValue == other.baselineShiftValue; + && *baselineShiftValue == *other.baselineShiftValue; } StyleResourceData::StyleResourceData() diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/SVGRenderStyleDefs.h b/chromium/third_party/WebKit/Source/core/rendering/style/SVGRenderStyleDefs.h index 9b32f78a578..abd12379dd6 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/SVGRenderStyleDefs.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/SVGRenderStyleDefs.h @@ -29,6 +29,7 @@ #define SVGRenderStyleDefs_h #include "core/svg/SVGLength.h" +#include "core/svg/SVGLengthList.h" #include "core/svg/SVGPaint.h" #include "wtf/OwnPtr.h" #include "wtf/PassOwnPtr.h" @@ -103,10 +104,6 @@ namespace WebCore { typedef unsigned EPaintOrder; const unsigned PO_NORMAL = PT_FILL | PT_STROKE << 2 | PT_MARKERS << 4; - class CSSValue; - class CSSValueList; - class SVGPaint; - // Inherited/Non-Inherited Style Datastructures class StyleFillData : public RefCounted<StyleFillData> { public: @@ -146,9 +143,9 @@ namespace WebCore { float opacity; float miterLimit; - SVGLength width; - SVGLength dashOffset; - Vector<SVGLength> dashArray; + RefPtr<SVGLength> width; + RefPtr<SVGLength> dashOffset; + RefPtr<SVGLengthList> dashArray; SVGPaint::SVGPaintType paintType; Color paintColor; @@ -181,24 +178,6 @@ namespace WebCore { StyleStopData(const StyleStopData&); }; - class StyleTextData : public RefCounted<StyleTextData> { - public: - static PassRefPtr<StyleTextData> create() { return adoptRef(new StyleTextData); } - PassRefPtr<StyleTextData> copy() const { return adoptRef(new StyleTextData(*this)); } - - bool operator==(const StyleTextData& other) const; - bool operator!=(const StyleTextData& other) const - { - return !(*this == other); - } - - SVGLength kerning; - - private: - StyleTextData(); - StyleTextData(const StyleTextData&); - }; - // Note: the rule for this class is, *no inheritance* of these props class StyleMiscData : public RefCounted<StyleMiscData> { public: @@ -215,8 +194,7 @@ namespace WebCore { float floodOpacity; Color lightingColor; - // non-inherited text stuff lives here not in StyleTextData. - SVGLength baselineShiftValue; + RefPtr<SVGLength> baselineShiftValue; private: StyleMiscData(); @@ -235,9 +213,9 @@ namespace WebCore { return !(*this == other); } - String clipper; - String filter; - String masker; + AtomicString clipper; + AtomicString filter; + AtomicString masker; private: StyleResourceData(); @@ -256,9 +234,9 @@ namespace WebCore { return !(*this == other); } - String markerStart; - String markerMid; - String markerEnd; + AtomicString markerStart; + AtomicString markerMid; + AtomicString markerEnd; private: StyleInheritedResourceData(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/ShadowData.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/ShadowData.cpp index 7f81d909f6b..d89b03e74e8 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/ShadowData.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/ShadowData.cpp @@ -41,7 +41,7 @@ ShadowData ShadowData::blend(const ShadowData& from, double progress) const return *this; return ShadowData(WebCore::blend(from.location(), location(), progress), - clampTo<int>(WebCore::blend(from.blur(), blur(), progress), 0), + clampTo(WebCore::blend(from.blur(), blur(), progress), 0.0f), WebCore::blend(from.spread(), spread(), progress), style(), WebCore::blend(from.color(), color(), progress)); diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/ShadowData.h b/chromium/third_party/WebKit/Source/core/rendering/style/ShadowData.h index 574b3f8214e..fa5a063cf34 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/ShadowData.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/ShadowData.h @@ -25,7 +25,7 @@ #ifndef ShadowData_h #define ShadowData_h -#include "platform/geometry/IntPoint.h" +#include "platform/geometry/FloatPoint.h" #include "platform/graphics/Color.h" namespace WebCore { @@ -36,7 +36,7 @@ enum ShadowStyle { Normal, Inset }; class ShadowData { WTF_MAKE_FAST_ALLOCATED; public: - ShadowData(const IntPoint& location, int blur, int spread, ShadowStyle style, const Color& color) + ShadowData(const FloatPoint& location, float blur, float spread, ShadowStyle style, const Color& color) : m_location(location) , m_blur(blur) , m_spread(spread) @@ -50,18 +50,19 @@ public: ShadowData blend(const ShadowData& from, double progress) const; - 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; } + float x() const { return m_location.x(); } + float y() const { return m_location.y(); } + FloatPoint location() const { return m_location; } + float blur() const { return m_blur; } + float spread() const { return m_spread; } ShadowStyle style() const { return m_style; } const Color& color() const { return m_color; } private: - IntPoint m_location; - int m_blur; - int m_spread; + FloatPoint m_location; + float m_blur; + float m_spread; + // FIXME: We should use StyleColor here to allow currentColor to work correctly with visited links Color m_color; ShadowStyle m_style; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/ShadowList.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/ShadowList.cpp index 675effec90b..b0f414a1162 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/ShadowList.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/ShadowList.cpp @@ -32,11 +32,10 @@ #include "core/rendering/style/ShadowList.h" #include "platform/geometry/FloatRect.h" -#include "platform/geometry/LayoutRect.h" namespace WebCore { -static inline void calculateShadowExtent(const ShadowList* shadowList, int additionalOutlineSize, int& shadowLeft, int& shadowRight, int& shadowTop, int& shadowBottom) +static inline void calculateShadowExtent(const ShadowList* shadowList, float additionalOutlineSize, float& shadowLeft, float& shadowRight, float& shadowTop, float& shadowBottom) { ASSERT(shadowList); size_t shadowCount = shadowList->shadows().size(); @@ -44,7 +43,7 @@ static inline void calculateShadowExtent(const ShadowList* shadowList, int addit const ShadowData& shadow = shadowList->shadows()[i]; if (shadow.style() == Inset) continue; - int blurAndSpread = shadow.blur() + shadow.spread() + additionalOutlineSize; + float blurAndSpread = shadow.blur() + shadow.spread() + additionalOutlineSize; shadowLeft = std::min(shadow.x() - blurAndSpread, shadowLeft); shadowRight = std::max(shadow.x() + blurAndSpread, shadowRight); shadowTop = std::min(shadow.y() - blurAndSpread, shadowTop); @@ -52,25 +51,19 @@ static inline void calculateShadowExtent(const ShadowList* shadowList, int addit } } -void ShadowList::adjustRectForShadow(LayoutRect& rect, int additionalOutlineSize) const +void ShadowList::adjustRectForShadow(LayoutRect& rect, float additionalOutlineSize) const { - int shadowLeft = 0; - int shadowRight = 0; - int shadowTop = 0; - int shadowBottom = 0; - calculateShadowExtent(this, additionalOutlineSize, shadowLeft, shadowRight, shadowTop, shadowBottom); - - rect.move(shadowLeft, shadowTop); - rect.setWidth(rect.width() - shadowLeft + shadowRight); - rect.setHeight(rect.height() - shadowTop + shadowBottom); + FloatRect floatRect(rect); + adjustRectForShadow(floatRect); + rect = LayoutRect(floatRect); } -void ShadowList::adjustRectForShadow(FloatRect& rect, int additionalOutlineSize) const +void ShadowList::adjustRectForShadow(FloatRect& rect, float additionalOutlineSize) const { - int shadowLeft = 0; - int shadowRight = 0; - int shadowTop = 0; - int shadowBottom = 0; + float shadowLeft = 0; + float shadowRight = 0; + float shadowTop = 0; + float shadowBottom = 0; calculateShadowExtent(this, additionalOutlineSize, shadowLeft, shadowRight, shadowTop, shadowBottom); rect.move(shadowLeft, shadowTop); @@ -83,12 +76,12 @@ PassRefPtr<ShadowList> ShadowList::blend(const ShadowList* from, const ShadowLis size_t fromLength = from ? from->shadows().size() : 0; size_t toLength = to ? to->shadows().size() : 0; if (!fromLength && !toLength) - return 0; + return nullptr; ShadowDataVector shadows; - DEFINE_STATIC_LOCAL(ShadowData, defaultShadowData, (IntPoint(), 0, 0, Normal, Color::transparent)); - DEFINE_STATIC_LOCAL(ShadowData, defaultInsetShadowData, (IntPoint(), 0, 0, Inset, Color::transparent)); + DEFINE_STATIC_LOCAL(ShadowData, defaultShadowData, (FloatPoint(), 0, 0, Normal, Color::transparent)); + DEFINE_STATIC_LOCAL(ShadowData, defaultInsetShadowData, (FloatPoint(), 0, 0, Inset, Color::transparent)); size_t maxLength = std::max(fromLength, toLength); for (size_t i = 0; i < maxLength; ++i) { diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/ShadowList.h b/chromium/third_party/WebKit/Source/core/rendering/style/ShadowList.h index 12acedf4801..6a1a4c1c9ad 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/ShadowList.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/ShadowList.h @@ -32,6 +32,7 @@ #define ShadowList_h #include "core/rendering/style/ShadowData.h" +#include "platform/geometry/LayoutRect.h" #include "wtf/RefCounted.h" #include "wtf/Vector.h" @@ -57,8 +58,8 @@ public: static PassRefPtr<ShadowList> blend(const ShadowList* from, const ShadowList* to, double progress); - void adjustRectForShadow(LayoutRect&, int additionalOutlineSize = 0) const; - void adjustRectForShadow(FloatRect&, int additionalOutlineSize = 0) const; + void adjustRectForShadow(LayoutRect&, float additionalOutlineSize = 0) const; + void adjustRectForShadow(FloatRect&, float additionalOutlineSize = 0) const; private: ShadowList(ShadowDataVector& shadows) diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/ShapeValue.h b/chromium/third_party/WebKit/Source/core/rendering/style/ShapeValue.h index 6b872807dce..dc12b4f1ff8 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/ShapeValue.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/ShapeValue.h @@ -44,23 +44,17 @@ public: // The Auto value is defined by a null ShapeValue* Shape, Box, - Outside, Image }; - static PassRefPtr<ShapeValue> createShapeValue(PassRefPtr<BasicShape> shape) + static PassRefPtr<ShapeValue> createShapeValue(PassRefPtr<BasicShape> shape, CSSBoxType cssBox) { - return adoptRef(new ShapeValue(shape)); + return adoptRef(new ShapeValue(shape, cssBox)); } - static PassRefPtr<ShapeValue> createOutsideValue() + static PassRefPtr<ShapeValue> createBoxShapeValue(CSSBoxType cssBox) { - return adoptRef(new ShapeValue(Outside)); - } - - static PassRefPtr<ShapeValue> createLayoutBoxValue(LayoutBox layoutBox) - { - return adoptRef(new ShapeValue(layoutBox)); + return adoptRef(new ShapeValue(cssBox)); } static PassRefPtr<ShapeValue> createImageValue(PassRefPtr<StyleImage> image) @@ -72,39 +66,45 @@ public: BasicShape* shape() const { return m_shape.get(); } StyleImage* image() const { return m_image.get(); } - bool isImageValid() const { return image() && image()->cachedImage() && image()->cachedImage()->hasImage(); } + bool isImageValid() const + { + if (!image()) + return false; + if (image()->isImageResource() || image()->isImageResourceSet()) + return image()->cachedImage() && image()->cachedImage()->hasImage(); + return image()->isGeneratedImage(); + } void setImage(PassRefPtr<StyleImage> image) { ASSERT(type() == Image); if (m_image != image) m_image = image; } - LayoutBox layoutBox() const { return m_layoutBox; } - void setLayoutBox(LayoutBox layoutBox) { m_layoutBox = layoutBox; } + CSSBoxType cssBox() const { return m_cssBox; } - bool operator==(const ShapeValue& other) const { return type() == other.type(); } + bool operator==(const ShapeValue& other) const; private: - ShapeValue(PassRefPtr<BasicShape> shape) + ShapeValue(PassRefPtr<BasicShape> shape, CSSBoxType cssBox) : m_type(Shape) , m_shape(shape) - , m_layoutBox(ContentBox) + , m_cssBox(cssBox) { } ShapeValue(ShapeValueType type) : m_type(type) - , m_layoutBox(ContentBox) + , m_cssBox(BoxMissing) { } ShapeValue(PassRefPtr<StyleImage> image) : m_type(Image) , m_image(image) - , m_layoutBox(ContentBox) + , m_cssBox(ContentBox) { } - ShapeValue(LayoutBox layoutBox) + ShapeValue(CSSBoxType cssBox) : m_type(Box) - , m_layoutBox(layoutBox) + , m_cssBox(cssBox) { } @@ -112,9 +112,27 @@ private: ShapeValueType m_type; RefPtr<BasicShape> m_shape; RefPtr<StyleImage> m_image; - LayoutBox m_layoutBox; + CSSBoxType m_cssBox; }; +inline bool ShapeValue::operator==(const ShapeValue& other) const +{ + if (type() != other.type()) + return false; + + switch (type()) { + case Shape: + return shape() == other.shape() && cssBox() == other.cssBox(); + case Box: + return cssBox() == other.cssBox(); + case Image: + return image() == other.image(); + } + + ASSERT_NOT_REACHED(); + return false; +} + } #endif diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleBackgroundData.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/StyleBackgroundData.cpp index d0b7ba4ff27..1dcfc53fb58 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleBackgroundData.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleBackgroundData.cpp @@ -46,4 +46,9 @@ bool StyleBackgroundData::operator==(const StyleBackgroundData& o) const return m_background == o.m_background && m_color == o.m_color && m_outline == o.m_outline; } +bool StyleBackgroundData::visuallyEqual(const StyleBackgroundData& o) const +{ + return m_background == o.m_background && m_color == o.m_color && m_outline.visuallyEqual(o.m_outline); +} + } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleBackgroundData.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleBackgroundData.h index fda242f38f2..f25efbd9f05 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleBackgroundData.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleBackgroundData.h @@ -45,8 +45,10 @@ public: return !(*this == o); } + bool visuallyEqual(const StyleBackgroundData&) const; + const FillLayer& background() const { return m_background; } - const Color& color() const { return m_color; } + const StyleColor& color() const { return m_color; } const OutlineValue& outline() const { return m_outline; } private: @@ -56,7 +58,7 @@ private: StyleBackgroundData(const StyleBackgroundData&); FillLayer m_background; - Color m_color; + StyleColor m_color; OutlineValue m_outline; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleBoxData.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleBoxData.h index 9b2296641df..6814b3a92e7 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleBoxData.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleBoxData.h @@ -43,16 +43,16 @@ public: return !(*this == o); } - Length width() const { return m_width; } - Length height() const { return m_height; } + const Length& width() const { return m_width; } + const Length& height() const { return m_height; } - Length minWidth() const { return m_minWidth; } - Length minHeight() const { return m_minHeight; } + const Length& minWidth() const { return m_minWidth; } + const Length& minHeight() const { return m_minHeight; } - Length maxWidth() const { return m_maxWidth; } - Length maxHeight() const { return m_maxHeight; } + const Length& maxWidth() const { return m_maxWidth; } + const Length& maxHeight() const { return m_maxHeight; } - Length verticalAlign() const { return m_verticalAlign; } + const Length& verticalAlign() const { return m_verticalAlign; } int zIndex() const { return m_zIndex; } bool hasAutoZIndex() const { return m_hasAutoZIndex; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleCustomFilterProgram.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/StyleCustomFilterProgram.cpp deleted file mode 100644 index 31c3d64d662..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleCustomFilterProgram.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2013 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 "core/rendering/style/StyleCustomFilterProgram.h" - -#include "core/rendering/style/StyleCustomFilterProgramCache.h" - -namespace WebCore { - -StyleCustomFilterProgram::~StyleCustomFilterProgram() -{ - if (m_cache) - m_cache->remove(this); -} - -} // namespace WebCore - - diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleCustomFilterProgram.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleCustomFilterProgram.h deleted file mode 100644 index d79cf6368f5..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleCustomFilterProgram.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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 StyleCustomFilterProgram_h -#define StyleCustomFilterProgram_h - -#include "core/fetch/ResourceClient.h" -#include "core/fetch/ResourcePtr.h" -#include "core/fetch/ShaderResource.h" -#include "core/rendering/style/StyleShader.h" -#include "platform/graphics/filters/custom/CustomFilterProgram.h" -#include "platform/weborigin/KURL.h" -#include "wtf/FastAllocBase.h" - -namespace WebCore { - -// CSS Shaders - -class StyleCustomFilterProgramCache; - -class StyleCustomFilterProgram : public CustomFilterProgram, public ResourceClient { - WTF_MAKE_FAST_ALLOCATED; -public: - static PassRefPtr<StyleCustomFilterProgram> create(KURL vertexShaderURL, PassRefPtr<StyleShader> vertexShader, - KURL fragmentShaderURL, PassRefPtr<StyleShader> fragmentShader, CustomFilterProgramType programType, - const CustomFilterProgramMixSettings& mixSettings, CustomFilterMeshType meshType) - { - return adoptRef(new StyleCustomFilterProgram(vertexShaderURL, vertexShader, fragmentShaderURL, fragmentShader, programType, mixSettings, meshType)); - } - - void setVertexShader(PassRefPtr<StyleShader> shader) - { - // The shader is immutable while in the cache. - ASSERT(!m_cache); - m_vertexShader = shader; - } - StyleShader* vertexShader() const { return m_vertexShader.get(); } - - void setFragmentShader(PassRefPtr<StyleShader> shader) - { - // The shader is immutable while in the cache. - ASSERT(!m_cache); - m_fragmentShader = shader; - } - StyleShader* fragmentShader() const { return m_fragmentShader.get(); } - - virtual String vertexShaderString() const - { - ASSERT(isLoaded()); - return m_cachedVertexShader.get() ? m_cachedVertexShader->shaderString() : String(); - } - - virtual String fragmentShaderString() const - { - ASSERT(isLoaded()); - return m_cachedFragmentShader.get() ? m_cachedFragmentShader->shaderString() : String(); - } - - virtual bool isLoaded() const - { - // Do not use the Resource:isLoaded method here, because it actually means !isLoading(), - // so missing and canceled resources will have isLoaded set to true, even if they are not loaded yet. - ASSERT(!m_vertexShader || m_vertexShader->isShaderResource()); - ASSERT(!m_fragmentShader || m_fragmentShader->isShaderResource()); - - // If we failed to create resources for the vertex shader or the - // fragment shader, they won't be set here. - // This can happen if the ResourceFetcher is no longer accepting fetch - // requests because the page is being torn down. - if (!m_vertexShader && !m_fragmentShader) - return false; - - ASSERT(m_cachedVertexShader.get() || m_cachedFragmentShader.get()); - return (!m_cachedVertexShader.get() || m_isVertexShaderLoaded) - && (!m_cachedFragmentShader.get() || m_isFragmentShaderLoaded); - } - - virtual void willHaveClients() - { - if (m_vertexShader) { - m_cachedVertexShader = m_vertexShader->resource(); - m_cachedVertexShader->addClient(this); - } - if (m_fragmentShader) { - m_cachedFragmentShader = m_fragmentShader->resource(); - m_cachedFragmentShader->addClient(this); - } - } - - virtual void didRemoveLastClient() - { - if (m_cachedVertexShader.get()) { - m_cachedVertexShader->removeClient(this); - m_cachedVertexShader = 0; - m_isVertexShaderLoaded = false; - } - if (m_cachedFragmentShader.get()) { - m_cachedFragmentShader->removeClient(this); - m_cachedFragmentShader = 0; - m_isFragmentShaderLoaded = false; - } - } - - virtual void notifyFinished(Resource* resource) - { - if (resource->errorOccurred()) - return; - // Note that m_cachedVertexShader might be equal to m_cachedFragmentShader and it would only get one event in that case. - if (resource == m_cachedVertexShader.get()) - m_isVertexShaderLoaded = true; - if (resource == m_cachedFragmentShader.get()) - m_isFragmentShaderLoaded = true; - if (isLoaded()) - notifyClients(); - } - - bool hasPendingShaders() const - { - return (m_vertexShader && m_vertexShader->isPendingShader()) - || (m_fragmentShader && m_fragmentShader->isPendingShader()); - } - - // StyleCustomFilterProgramCache is responsible with updating the reference to the cache. - void setCache(StyleCustomFilterProgramCache* cache) { m_cache = cache; } - bool inCache() const { return m_cache; } - - KURL vertexShaderURL() const { return m_vertexShaderURL; } - KURL fragmentShaderURL() const { return m_fragmentShaderURL; } - -private: - StyleCustomFilterProgram(KURL vertexShaderURL, PassRefPtr<StyleShader> vertexShader, KURL fragmentShaderURL, PassRefPtr<StyleShader> fragmentShader, - CustomFilterProgramType programType, const CustomFilterProgramMixSettings& mixSettings, CustomFilterMeshType meshType) - : CustomFilterProgram(programType, mixSettings, meshType) - , m_vertexShader(vertexShader) - , m_fragmentShader(fragmentShader) - , m_vertexShaderURL(vertexShaderURL) - , m_fragmentShaderURL(fragmentShaderURL) - , m_cache(0) - , m_isVertexShaderLoaded(false) - , m_isFragmentShaderLoaded(false) - { - } - - ~StyleCustomFilterProgram(); - - RefPtr<StyleShader> m_vertexShader; - RefPtr<StyleShader> m_fragmentShader; - - ResourcePtr<ShaderResource> m_cachedVertexShader; - ResourcePtr<ShaderResource> m_cachedFragmentShader; - - // The URLs form the key of the StyleCustomFilterProgram in the cache and are used - // to lookup the StyleCustomFilterProgram when it's removed from the cache. - KURL m_vertexShaderURL; - KURL m_fragmentShaderURL; - - // The Cache is responsible of invalidating this reference. - StyleCustomFilterProgramCache* m_cache; - - bool m_isVertexShaderLoaded; - bool m_isFragmentShaderLoaded; -}; - -} // namespace WebCore - - -#endif // StyleCustomFilterProgram_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleCustomFilterProgramCache.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/StyleCustomFilterProgramCache.cpp deleted file mode 100644 index 87d3aba9b66..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleCustomFilterProgramCache.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2013 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 "core/rendering/style/StyleCustomFilterProgramCache.h" - -#include "core/rendering/style/StyleCustomFilterProgram.h" - -namespace WebCore { - -static CustomFilterProgramInfo programCacheKey(StyleCustomFilterProgram* program) -{ - ASSERT(program->vertexShaderURL().isValid() || program->fragmentShaderURL().isValid()); - return CustomFilterProgramInfo(program->vertexShaderURL().string(), program->fragmentShaderURL().string(), - program->programType(), program->mixSettings(), program->meshType()); -} - -PassOwnPtr<StyleCustomFilterProgramCache> StyleCustomFilterProgramCache::create() -{ - return adoptPtr(new StyleCustomFilterProgramCache()); -} - -StyleCustomFilterProgramCache::~StyleCustomFilterProgramCache() -{ - // Make sure the programs are not calling back into this object. - for (CacheMap::iterator iter = m_cache.begin(), end = m_cache.end(); iter != end; ++iter) - iter->value->setCache(0); -} - -StyleCustomFilterProgram* StyleCustomFilterProgramCache::lookup(const CustomFilterProgramInfo& programInfo) const -{ - CacheMap::const_iterator iter = m_cache.find(programInfo); - return iter != m_cache.end() ? iter->value : 0; -} - -StyleCustomFilterProgram* StyleCustomFilterProgramCache::lookup(StyleCustomFilterProgram* program) const -{ - return lookup(programCacheKey(program)); -} - -void StyleCustomFilterProgramCache::add(StyleCustomFilterProgram* program) -{ - CustomFilterProgramInfo key = programCacheKey(program); - ASSERT(m_cache.find(key) == m_cache.end()); - m_cache.set(key, program); - program->setCache(this); -} - -void StyleCustomFilterProgramCache::remove(StyleCustomFilterProgram* program) -{ - CacheMap::iterator iter = m_cache.find(programCacheKey(program)); - ASSERT_WITH_SECURITY_IMPLICATION(iter != m_cache.end()); - m_cache.remove(iter); -} - - -} // namespace WebCore - - diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleCustomFilterProgramCache.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleCustomFilterProgramCache.h deleted file mode 100644 index 2bc1652d0e6..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleCustomFilterProgramCache.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2013 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 StyleCustomFilterProgramCache_h -#define StyleCustomFilterProgramCache_h - -#include "platform/graphics/filters/custom/CustomFilterProgramInfo.h" -#include "wtf/FastAllocBase.h" -#include "wtf/HashMap.h" - -namespace WebCore { - -class StyleCustomFilterProgram; -class CustomFilterProgramInfo; - -class StyleCustomFilterProgramCache { - WTF_MAKE_FAST_ALLOCATED; -public: - static PassOwnPtr<StyleCustomFilterProgramCache> create(); - ~StyleCustomFilterProgramCache(); - - // Lookups a StyleCustomFilterProgram that has similar parameters with the specified program. - StyleCustomFilterProgram* lookup(StyleCustomFilterProgram*) const; - StyleCustomFilterProgram* lookup(const CustomFilterProgramInfo&) const; - - void add(StyleCustomFilterProgram*); - void remove(StyleCustomFilterProgram*); - -private: - StyleCustomFilterProgramCache() { } - - typedef HashMap<CustomFilterProgramInfo, StyleCustomFilterProgram*> CacheMap; - CacheMap m_cache; -}; - -} // namespace WebCore - - -#endif // StyleCustomFilterProgramCache_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleDeprecatedFlexibleBoxData.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/StyleDeprecatedFlexibleBoxData.cpp index 4b3ff280e23..2c030fcc86a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleDeprecatedFlexibleBoxData.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleDeprecatedFlexibleBoxData.cpp @@ -28,8 +28,8 @@ namespace WebCore { StyleDeprecatedFlexibleBoxData::StyleDeprecatedFlexibleBoxData() : flex(RenderStyle::initialBoxFlex()) - , flex_group(RenderStyle::initialBoxFlexGroup()) - , ordinal_group(RenderStyle::initialBoxOrdinalGroup()) + , flexGroup(RenderStyle::initialBoxFlexGroup()) + , ordinalGroup(RenderStyle::initialBoxOrdinalGroup()) , align(RenderStyle::initialBoxAlign()) , pack(RenderStyle::initialBoxPack()) , orient(RenderStyle::initialBoxOrient()) @@ -40,8 +40,8 @@ StyleDeprecatedFlexibleBoxData::StyleDeprecatedFlexibleBoxData() StyleDeprecatedFlexibleBoxData::StyleDeprecatedFlexibleBoxData(const StyleDeprecatedFlexibleBoxData& o) : RefCounted<StyleDeprecatedFlexibleBoxData>() , flex(o.flex) - , flex_group(o.flex_group) - , ordinal_group(o.ordinal_group) + , flexGroup(o.flexGroup) + , ordinalGroup(o.ordinalGroup) , align(o.align) , pack(o.pack) , orient(o.orient) @@ -51,9 +51,7 @@ StyleDeprecatedFlexibleBoxData::StyleDeprecatedFlexibleBoxData(const StyleDeprec bool StyleDeprecatedFlexibleBoxData::operator==(const StyleDeprecatedFlexibleBoxData& o) const { - return flex == o.flex && flex_group == o.flex_group && - ordinal_group == o.ordinal_group && align == o.align && - pack == o.pack && orient == o.orient && lines == o.lines; + return flex == o.flex && flexGroup == o.flexGroup && ordinalGroup == o.ordinalGroup && align == o.align && pack == o.pack && orient == o.orient && lines == o.lines; } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleDeprecatedFlexibleBoxData.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleDeprecatedFlexibleBoxData.h index 501157cc15d..adfee1f1717 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleDeprecatedFlexibleBoxData.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleDeprecatedFlexibleBoxData.h @@ -42,8 +42,8 @@ public: } float flex; - unsigned int flex_group; - unsigned int ordinal_group; + unsigned flexGroup; + unsigned ordinalGroup; unsigned align : 3; // EBoxAlignment unsigned pack: 2; // EBoxPack diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleDifference.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleDifference.h new file mode 100644 index 00000000000..d8418217b83 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleDifference.h @@ -0,0 +1,80 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef StyleDifference_h +#define StyleDifference_h + +#include "wtf/Assertions.h" + +namespace WebCore { + +// This class represents the difference between two computed styles (RenderStyle). +// The difference can be combination of 3 types according to the actions needed: +// - Difference needing layout +// - Difference needing repaint +// - Difference needing recompositing layers +class StyleDifference { +public: + StyleDifference() + : m_needsRecompositeLayer(false) + , m_repaintType(NoRepaint) + , m_layoutType(NoLayout) { } + + // The two styles are identical. + bool hasNoChange() const { return !m_needsRecompositeLayer && !m_repaintType && !m_layoutType; } + + // The layer needs its position and transform updated. Implied by other repaint and layout flags. + bool needsRecompositeLayer() const { return m_needsRecompositeLayer || needsRepaint() || needsLayout(); } + void setNeedsRecompositeLayer() { m_needsRecompositeLayer = true; } + + bool needsRepaint() const { return m_repaintType != NoRepaint; } + void clearNeedsRepaint() { m_repaintType = NoRepaint; } + + // The object just needs to be repainted. + bool needsRepaintObject() const { return m_repaintType == RepaintObject; } + void setNeedsRepaintObject() + { + ASSERT(!needsRepaintLayer()); + m_repaintType = RepaintObject; + } + + // The layer and its descendant layers need to be repainted. + bool needsRepaintLayer() const { return m_repaintType == RepaintLayer; } + void setNeedsRepaintLayer() { m_repaintType = RepaintLayer; } + + bool needsLayout() const { return m_layoutType != NoLayout; } + void clearNeedsLayout() { m_layoutType = NoLayout; } + + // The offset of this positioned object has been updated. + bool needsPositionedMovementLayout() const { return m_layoutType == PositionedMovement; } + void setNeedsPositionedMovementLayout() + { + ASSERT(!needsFullLayout()); + m_layoutType = PositionedMovement; + } + + bool needsFullLayout() const { return m_layoutType == FullLayout; } + void setNeedsFullLayout() { m_layoutType = FullLayout; } + +private: + unsigned m_needsRecompositeLayer : 1; + + enum RepaintType { + NoRepaint = 0, + RepaintObject, + RepaintLayer + }; + unsigned m_repaintType : 2; + + enum LayoutType { + NoLayout = 0, + PositionedMovement, + FullLayout + }; + unsigned m_layoutType : 2; +}; + +} // namespace WebCore + +#endif // StyleDifference_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedImage.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedImage.cpp index 31dc65a0452..e53dc04ada8 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedImage.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedImage.cpp @@ -24,6 +24,7 @@ #include "config.h" #include "core/rendering/style/StyleFetchedImage.h" +#include "core/css/CSSImageValue.h" #include "core/fetch/ImageResource.h" #include "core/rendering/RenderObject.h" @@ -41,12 +42,12 @@ StyleFetchedImage::~StyleFetchedImage() m_image->removeClient(this); } -PassRefPtr<CSSValue> StyleFetchedImage::cssValue() const +PassRefPtrWillBeRawPtr<CSSValue> StyleFetchedImage::cssValue() const { - return CSSPrimitiveValue::create(m_image->url().string(), CSSPrimitiveValue::CSS_URI); + return CSSImageValue::create(m_image->url(), const_cast<StyleFetchedImage*>(this)); } -bool StyleFetchedImage::canRender(const RenderObject* renderer, float multiplier) const +bool StyleFetchedImage::canRender(const RenderObject& renderer, float multiplier) const { return m_image->canRender(renderer, multiplier); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedImage.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedImage.h index e783439b195..e74c26c9168 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedImage.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedImage.h @@ -32,28 +32,28 @@ namespace WebCore { class ImageResource; -class StyleFetchedImage : public StyleImage, private ImageResourceClient { +class StyleFetchedImage FINAL : public StyleImage, private ImageResourceClient { WTF_MAKE_FAST_ALLOCATED; public: static PassRefPtr<StyleFetchedImage> create(ImageResource* image) { return adoptRef(new StyleFetchedImage(image)); } virtual ~StyleFetchedImage(); - virtual WrappedImagePtr data() const { return m_image.get(); } + virtual WrappedImagePtr data() const OVERRIDE { return m_image.get(); } - virtual PassRefPtr<CSSValue> cssValue() const; + virtual PassRefPtrWillBeRawPtr<CSSValue> cssValue() const OVERRIDE; - virtual bool canRender(const RenderObject*, float multiplier) const; - virtual bool isLoaded() const; - virtual bool errorOccurred() const; + virtual bool canRender(const RenderObject&, float multiplier) const OVERRIDE; + virtual bool isLoaded() const OVERRIDE; + virtual bool errorOccurred() const OVERRIDE; virtual LayoutSize imageSize(const RenderObject*, float multiplier) const OVERRIDE; - 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 bool imageHasRelativeWidth() const OVERRIDE; + virtual bool imageHasRelativeHeight() const OVERRIDE; + virtual void computeIntrinsicDimensions(const RenderObject*, Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio) OVERRIDE; + virtual bool usesImageContainerSize() const OVERRIDE; + virtual void setContainerSizeForRenderer(const RenderObject*, const IntSize&, float) OVERRIDE; + virtual void addClient(RenderObject*) OVERRIDE; + virtual void removeClient(RenderObject*) OVERRIDE; + virtual PassRefPtr<Image> image(RenderObject*, const IntSize&) const OVERRIDE; virtual bool knownToBeOpaque(const RenderObject*) const OVERRIDE; virtual ImageResource* cachedImage() const OVERRIDE { return m_image.get(); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedImageSet.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedImageSet.cpp index 04a8d9d5961..2aacd2fedd9 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedImageSet.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedImageSet.cpp @@ -47,12 +47,12 @@ StyleFetchedImageSet::~StyleFetchedImageSet() m_bestFitImage->removeClient(this); } -PassRefPtr<CSSValue> StyleFetchedImageSet::cssValue() const +PassRefPtrWillBeRawPtr<CSSValue> StyleFetchedImageSet::cssValue() const { return m_imageSetValue; } -bool StyleFetchedImageSet::canRender(const RenderObject* renderer, float multiplier) const +bool StyleFetchedImageSet::canRender(const RenderObject& renderer, float multiplier) const { return m_bestFitImage->canRender(renderer, multiplier); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedImageSet.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedImageSet.h index 873c14299ef..cee20a65846 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedImageSet.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedImageSet.h @@ -38,7 +38,7 @@ class CSSImageSetValue; // This class keeps one cached image and has access to a set of alternatives. -class StyleFetchedImageSet : public StyleImage, private ImageResourceClient { +class StyleFetchedImageSet FINAL : public StyleImage, private ImageResourceClient { WTF_MAKE_FAST_ALLOCATED; public: static PassRefPtr<StyleFetchedImageSet> create(ImageResource* image, float imageScaleFactor, CSSImageSetValue* value) @@ -47,28 +47,28 @@ public: } virtual ~StyleFetchedImageSet(); - virtual PassRefPtr<CSSValue> cssValue() const; + virtual PassRefPtrWillBeRawPtr<CSSValue> cssValue() const OVERRIDE; // 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(); } + virtual WrappedImagePtr data() const OVERRIDE { return m_bestFitImage.get(); } void clearImageSetValue() { m_imageSetValue = 0; } - virtual bool canRender(const RenderObject*, float multiplier) const; - virtual bool isLoaded() const; - virtual bool errorOccurred() const; - virtual LayoutSize 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; } + virtual bool canRender(const RenderObject&, float multiplier) const OVERRIDE; + virtual bool isLoaded() const OVERRIDE; + virtual bool errorOccurred() const OVERRIDE; + virtual LayoutSize imageSize(const RenderObject*, float multiplier) const OVERRIDE; + virtual bool imageHasRelativeWidth() const OVERRIDE; + virtual bool imageHasRelativeHeight() const OVERRIDE; + virtual void computeIntrinsicDimensions(const RenderObject*, Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio) OVERRIDE; + virtual bool usesImageContainerSize() const OVERRIDE; + virtual void setContainerSizeForRenderer(const RenderObject*, const IntSize&, float) OVERRIDE; + virtual void addClient(RenderObject*) OVERRIDE; + virtual void removeClient(RenderObject*) OVERRIDE; + virtual PassRefPtr<Image> image(RenderObject*, const IntSize&) const OVERRIDE; + virtual float imageScaleFactor() const OVERRIDE { return m_imageScaleFactor; } virtual bool knownToBeOpaque(const RenderObject*) const OVERRIDE; virtual ImageResource* cachedImage() const OVERRIDE { return m_bestFitImage.get(); } @@ -77,6 +77,11 @@ private: ResourcePtr<ImageResource> m_bestFitImage; float m_imageScaleFactor; + + // FIXME: oilpan: Change to RawPtrWillBeMember when moving this class onto oilpan heap. + // Also add "if !ENABLE(OILPAN)" around clearImageSetValue above as well as around its + // caller since it should not be needed once both of the objects are on the heap and + // oilpan is enabled. CSSImageSetValue* m_imageSetValue; // Not retained; it owns us. }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedShader.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedShader.cpp deleted file mode 100644 index 13a8b98c36a..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedShader.cpp +++ /dev/null @@ -1,53 +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. - */ - -#include "config.h" - -#include "core/rendering/style/StyleFetchedShader.h" - -#include "core/css/CSSPrimitiveValue.h" -#include "core/fetch/ShaderResource.h" - -namespace WebCore { - - -StyleFetchedShader::StyleFetchedShader(ShaderResource* shader) - : m_shader(shader) -{ - m_isShaderResource = true; -} - -PassRefPtr<CSSValue> StyleFetchedShader::cssValue() const -{ - return CSSPrimitiveValue::create(m_shader->url().string(), CSSPrimitiveValue::CSS_URI); -} - -} // namespace WebCore - - diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedShader.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedShader.h deleted file mode 100644 index 104a90cc871..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleFetchedShader.h +++ /dev/null @@ -1,57 +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 StyleFetchedShader_h -#define StyleFetchedShader_h - -#include "core/fetch/ResourcePtr.h" -#include "core/rendering/style/StyleShader.h" - -namespace WebCore { - -class ShaderResource; - -class StyleFetchedShader : public StyleShader { -public: - // FIXME: Keep a reference to the actual ShaderResource in this class. - static PassRefPtr<StyleFetchedShader> create(ShaderResource* shader) { return adoptRef(new StyleFetchedShader(shader)); } - - virtual PassRefPtr<CSSValue> cssValue() const; - - virtual ShaderResource* resource() const { return m_shader.get(); } - -private: - StyleFetchedShader(ShaderResource*); - - ResourcePtr<ShaderResource> m_shader; -}; - -} - -#endif // StyleFetchedShader_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleGeneratedImage.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/StyleGeneratedImage.cpp index 2ec1c87de4e..f675fa5b0b5 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleGeneratedImage.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleGeneratedImage.cpp @@ -30,16 +30,16 @@ namespace WebCore { -StyleGeneratedImage::StyleGeneratedImage(PassRefPtr<CSSImageGeneratorValue> value) +StyleGeneratedImage::StyleGeneratedImage(PassRefPtrWillBeRawPtr<CSSImageGeneratorValue> value) : m_imageGeneratorValue(value) , m_fixedSize(m_imageGeneratorValue->isFixedSize()) { m_isGeneratedImage = true; } -PassRefPtr<CSSValue> StyleGeneratedImage::cssValue() const +PassRefPtrWillBeRawPtr<CSSValue> StyleGeneratedImage::cssValue() const { - return m_imageGeneratorValue; + return m_imageGeneratorValue.get(); } LayoutSize StyleGeneratedImage::imageSize(const RenderObject* renderer, float multiplier) const diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleGeneratedImage.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleGeneratedImage.h index bf93af475da..219f47e241d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleGeneratedImage.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleGeneratedImage.h @@ -31,32 +31,33 @@ namespace WebCore { class CSSValue; class CSSImageGeneratorValue; -class StyleGeneratedImage : public StyleImage { +class StyleGeneratedImage FINAL : public StyleImage { public: static PassRefPtr<StyleGeneratedImage> create(CSSImageGeneratorValue* value) { return adoptRef(new StyleGeneratedImage(value)); } - virtual WrappedImagePtr data() const { return m_imageGeneratorValue.get(); } + virtual WrappedImagePtr data() const OVERRIDE { return m_imageGeneratorValue.get(); } - virtual PassRefPtr<CSSValue> cssValue() const; + virtual PassRefPtrWillBeRawPtr<CSSValue> cssValue() const OVERRIDE; virtual LayoutSize imageSize(const RenderObject*, float multiplier) const OVERRIDE; - virtual bool imageHasRelativeWidth() const { return !m_fixedSize; } - virtual bool imageHasRelativeHeight() const { return !m_fixedSize; } - virtual void computeIntrinsicDimensions(const RenderObject*, Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio); - virtual bool usesImageContainerSize() const { return !m_fixedSize; } - virtual void setContainerSizeForRenderer(const RenderObject*, const IntSize& containerSize, float) { m_containerSize = containerSize; } - virtual void addClient(RenderObject*); - virtual void removeClient(RenderObject*); - virtual PassRefPtr<Image> image(RenderObject*, const IntSize&) const; + virtual bool imageHasRelativeWidth() const OVERRIDE { return !m_fixedSize; } + virtual bool imageHasRelativeHeight() const OVERRIDE { return !m_fixedSize; } + virtual void computeIntrinsicDimensions(const RenderObject*, Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio) OVERRIDE; + virtual bool usesImageContainerSize() const OVERRIDE { return !m_fixedSize; } + virtual void setContainerSizeForRenderer(const RenderObject*, const IntSize& containerSize, float) OVERRIDE { m_containerSize = containerSize; } + virtual void addClient(RenderObject*) OVERRIDE; + virtual void removeClient(RenderObject*) OVERRIDE; + virtual PassRefPtr<Image> image(RenderObject*, const IntSize&) const OVERRIDE; virtual bool knownToBeOpaque(const RenderObject*) const OVERRIDE; private: - StyleGeneratedImage(PassRefPtr<CSSImageGeneratorValue>); + StyleGeneratedImage(PassRefPtrWillBeRawPtr<CSSImageGeneratorValue>); - RefPtr<CSSImageGeneratorValue> m_imageGeneratorValue; + // FIXME: oilpan: change to member once StyleImage is moved to the oilpan heap + RefPtrWillBePersistent<CSSImageGeneratorValue> m_imageGeneratorValue; IntSize m_containerSize; bool m_fixedSize; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleGridData.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/StyleGridData.cpp index a3f8a348017..d323864b32b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleGridData.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleGridData.cpp @@ -31,8 +31,8 @@ namespace WebCore { StyleGridData::StyleGridData() - : m_gridDefinitionColumns(RenderStyle::initialGridDefinitionColumns()) - , m_gridDefinitionRows(RenderStyle::initialGridDefinitionRows()) + : m_gridTemplateColumns(RenderStyle::initialGridTemplateColumns()) + , m_gridTemplateRows(RenderStyle::initialGridTemplateRows()) , m_namedGridColumnLines(RenderStyle::initialNamedGridColumnLines()) , m_namedGridRowLines(RenderStyle::initialNamedGridRowLines()) , m_orderedNamedGridColumnLines(RenderStyle::initialOrderedNamedGridColumnLines()) @@ -48,8 +48,8 @@ StyleGridData::StyleGridData() StyleGridData::StyleGridData(const StyleGridData& o) : RefCounted<StyleGridData>() - , m_gridDefinitionColumns(o.m_gridDefinitionColumns) - , m_gridDefinitionRows(o.m_gridDefinitionRows) + , m_gridTemplateColumns(o.m_gridTemplateColumns) + , m_gridTemplateRows(o.m_gridTemplateRows) , m_namedGridColumnLines(o.m_namedGridColumnLines) , m_namedGridRowLines(o.m_namedGridRowLines) , m_orderedNamedGridColumnLines(o.m_orderedNamedGridColumnLines) diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleGridData.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleGridData.h index c7f5e5430e7..da14eaa2989 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleGridData.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleGridData.h @@ -46,7 +46,7 @@ public: bool operator==(const StyleGridData& o) const { - return m_gridDefinitionColumns == o.m_gridDefinitionColumns && m_gridDefinitionRows == o.m_gridDefinitionRows && m_gridAutoFlow == o.m_gridAutoFlow && m_gridAutoRows == o.m_gridAutoRows && m_gridAutoColumns == o.m_gridAutoColumns && m_namedGridColumnLines == o.m_namedGridColumnLines && m_namedGridRowLines == o.m_namedGridRowLines && m_orderedNamedGridColumnLines == o.m_orderedNamedGridColumnLines && m_orderedNamedGridRowLines == o.m_orderedNamedGridRowLines && m_namedGridArea == o.m_namedGridArea && m_namedGridArea == o.m_namedGridArea && m_namedGridAreaRowCount == o.m_namedGridAreaRowCount && m_namedGridAreaColumnCount == o.m_namedGridAreaColumnCount; + return m_gridTemplateColumns == o.m_gridTemplateColumns && m_gridTemplateRows == o.m_gridTemplateRows && m_gridAutoFlow == o.m_gridAutoFlow && m_gridAutoRows == o.m_gridAutoRows && m_gridAutoColumns == o.m_gridAutoColumns && m_namedGridColumnLines == o.m_namedGridColumnLines && m_namedGridRowLines == o.m_namedGridRowLines && m_orderedNamedGridColumnLines == o.m_orderedNamedGridColumnLines && m_orderedNamedGridRowLines == o.m_orderedNamedGridRowLines && m_namedGridArea == o.m_namedGridArea && m_namedGridArea == o.m_namedGridArea && m_namedGridAreaRowCount == o.m_namedGridAreaRowCount && m_namedGridAreaColumnCount == o.m_namedGridAreaColumnCount; } bool operator!=(const StyleGridData& o) const @@ -54,8 +54,8 @@ public: return !(*this == o); } - Vector<GridTrackSize> m_gridDefinitionColumns; - Vector<GridTrackSize> m_gridDefinitionRows; + Vector<GridTrackSize> m_gridTemplateColumns; + Vector<GridTrackSize> m_gridTemplateRows; NamedGridLinesMap m_namedGridColumnLines; NamedGridLinesMap m_namedGridRowLines; diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleImage.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleImage.h index bca329ac568..b487e2c33ce 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleImage.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleImage.h @@ -49,9 +49,9 @@ public: return data() == other.data(); } - virtual PassRefPtr<CSSValue> cssValue() const = 0; + virtual PassRefPtrWillBeRawPtr<CSSValue> cssValue() const = 0; - virtual bool canRender(const RenderObject*, float /*multiplier*/) const { return true; } + virtual bool canRender(const RenderObject&, float /*multiplier*/) const { return true; } virtual bool isLoaded() const { return true; } virtual bool errorOccurred() const { return false; } virtual LayoutSize imageSize(const RenderObject*, float multiplier) const = 0; @@ -73,16 +73,6 @@ public: ALWAYS_INLINE bool isGeneratedImage() const { return m_isGeneratedImage; } ALWAYS_INLINE bool isImageResourceSet() const { return m_isImageResourceSet; } - static bool imagesEquivalent(const StyleImage* image1, const StyleImage* image2) - { - if (image1 != image2) { - if (!image1 || !image2) - return false; - return *image1 == *image2; - } - return true; - } - protected: StyleImage() : m_isImageResource(false) diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleInheritedData.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/StyleInheritedData.cpp index 063e7d2286c..1b961aa497e 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleInheritedData.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleInheritedData.cpp @@ -32,6 +32,7 @@ StyleInheritedData::StyleInheritedData() , line_height(RenderStyle::initialLineHeight()) , color(RenderStyle::initialColor()) , visitedLinkColor(RenderStyle::initialColor()) + , textAutosizingMultiplier(1) { } @@ -47,6 +48,7 @@ StyleInheritedData::StyleInheritedData(const StyleInheritedData& o) , font(o.font) , color(o.color) , visitedLinkColor(o.visitedLinkColor) + , textAutosizingMultiplier(o.textAutosizingMultiplier) { } @@ -57,6 +59,7 @@ bool StyleInheritedData::operator==(const StyleInheritedData& o) const && color == o.color && visitedLinkColor == o.visitedLinkColor && horizontal_border_spacing == o.horizontal_border_spacing + && textAutosizingMultiplier == o.textAutosizingMultiplier && vertical_border_spacing == o.vertical_border_spacing; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleInheritedData.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleInheritedData.h index 11613a4abf7..7466a7c78fd 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleInheritedData.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleInheritedData.h @@ -56,6 +56,7 @@ public: Font font; Color color; Color visitedLinkColor; + float textAutosizingMultiplier; private: StyleInheritedData(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleMultiColData.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/StyleMultiColData.cpp index 90897bb28bf..f7a7c5337e5 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleMultiColData.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleMultiColData.cpp @@ -30,6 +30,7 @@ StyleMultiColData::StyleMultiColData() : m_width(0) , m_count(RenderStyle::initialColumnCount()) , m_gap(0) + , m_visitedLinkColumnRuleColor(StyleColor::currentColor()) , m_autoWidth(true) , m_autoCount(true) , m_normalGap(true) @@ -38,8 +39,6 @@ StyleMultiColData::StyleMultiColData() , m_breakBefore(RenderStyle::initialPageBreak()) , m_breakAfter(RenderStyle::initialPageBreak()) , m_breakInside(RenderStyle::initialPageBreak()) - , m_axis(RenderStyle::initialColumnAxis()) - , m_progression(RenderStyle::initialColumnProgression()) { } @@ -58,8 +57,6 @@ StyleMultiColData::StyleMultiColData(const StyleMultiColData& o) , m_breakBefore(o.m_breakBefore) , m_breakAfter(o.m_breakAfter) , m_breakInside(o.m_breakInside) - , m_axis(o.m_axis) - , m_progression(o.m_progression) { } @@ -69,8 +66,7 @@ bool StyleMultiColData::operator==(const StyleMultiColData& o) const && m_rule == o.m_rule && m_visitedLinkColumnRuleColor == o.m_visitedLinkColumnRuleColor && m_breakBefore == o.m_breakBefore && m_autoWidth == o.m_autoWidth && m_autoCount == o.m_autoCount && m_normalGap == o.m_normalGap && m_fill == o.m_fill && m_columnSpan == o.m_columnSpan - && m_breakAfter == o.m_breakAfter && m_breakInside == o.m_breakInside - && m_axis == o.m_axis && m_progression == o.m_progression; + && m_breakAfter == o.m_breakAfter && m_breakInside == o.m_breakInside; } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleMultiColData.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleMultiColData.h index fcf66802667..27441be85cd 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleMultiColData.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleMultiColData.h @@ -57,7 +57,7 @@ public: unsigned short m_count; float m_gap; BorderValue m_rule; - Color m_visitedLinkColumnRuleColor; + StyleColor m_visitedLinkColumnRuleColor; bool m_autoWidth : 1; bool m_autoCount : 1; @@ -67,8 +67,6 @@ public: unsigned m_breakBefore : 2; // EPageBreak unsigned m_breakAfter : 2; // EPageBreak unsigned m_breakInside : 2; // EPageBreak - unsigned m_axis : 2; // ColumnAxis - unsigned m_progression : 2; // ColumnProgression private: StyleMultiColData(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StylePendingImage.h b/chromium/third_party/WebKit/Source/core/rendering/style/StylePendingImage.h index 4589f59a63d..d735175bb68 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StylePendingImage.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StylePendingImage.h @@ -39,32 +39,32 @@ namespace WebCore { // style resolution, in order to avoid loading images that are not referenced by the final style. // They should never exist in a RenderStyle after it has been returned from the style selector. -class StylePendingImage : public StyleImage { +class StylePendingImage FINAL : public StyleImage { public: static PassRefPtr<StylePendingImage> create(CSSValue* value) { return adoptRef(new StylePendingImage(value)); } - virtual WrappedImagePtr data() const { return m_value; } + virtual WrappedImagePtr data() const OVERRIDE { return m_value; } - virtual PassRefPtr<CSSValue> cssValue() const { return m_value; } + virtual PassRefPtrWillBeRawPtr<CSSValue> cssValue() const OVERRIDE { return m_value; } CSSImageValue* cssImageValue() const { return m_value->isImageValue() ? toCSSImageValue(m_value) : 0; } CSSImageGeneratorValue* cssImageGeneratorValue() const { return m_value->isImageGeneratorValue() ? toCSSImageGeneratorValue(m_value) : 0; } CSSCursorImageValue* cssCursorImageValue() const { return m_value->isCursorImageValue() ? toCSSCursorImageValue(m_value) : 0; } CSSImageSetValue* cssImageSetValue() const { return m_value->isImageSetValue() ? toCSSImageSetValue(m_value) : 0; } virtual LayoutSize imageSize(const RenderObject*, float /*multiplier*/) const OVERRIDE { return LayoutSize(); } - virtual bool imageHasRelativeWidth() const { return false; } - virtual bool imageHasRelativeHeight() const { return false; } - virtual void computeIntrinsicDimensions(const RenderObject*, Length& /* intrinsicWidth */ , Length& /* intrinsicHeight */, FloatSize& /* intrinsicRatio */) { } - virtual bool usesImageContainerSize() const { return false; } - 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 bool imageHasRelativeWidth() const OVERRIDE { return false; } + virtual bool imageHasRelativeHeight() const OVERRIDE { return false; } + virtual void computeIntrinsicDimensions(const RenderObject*, Length& /* intrinsicWidth */ , Length& /* intrinsicHeight */, FloatSize& /* intrinsicRatio */) OVERRIDE { } + virtual bool usesImageContainerSize() const OVERRIDE { return false; } + virtual void setContainerSizeForRenderer(const RenderObject*, const IntSize&, float) OVERRIDE { } + virtual void addClient(RenderObject*) OVERRIDE { } + virtual void removeClient(RenderObject*) OVERRIDE { } + virtual PassRefPtr<Image> image(RenderObject*, const IntSize&) const OVERRIDE { ASSERT_NOT_REACHED(); - return 0; + return nullptr; } - virtual bool knownToBeOpaque(const RenderObject*) const { return false; } + virtual bool knownToBeOpaque(const RenderObject*) const OVERRIDE { return false; } private: StylePendingImage(CSSValue* value) diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StylePendingShader.h b/chromium/third_party/WebKit/Source/core/rendering/style/StylePendingShader.h deleted file mode 100644 index 1158e33a740..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StylePendingShader.h +++ /dev/null @@ -1,60 +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 StylePendingShader_h -#define StylePendingShader_h - -#include "core/css/CSSShaderValue.h" -#include "core/css/CSSValue.h" -#include "core/rendering/style/StyleShader.h" -#include "wtf/PassRefPtr.h" - -namespace WebCore { - -class WebKitCSSShaderValue; - -class StylePendingShader : public StyleShader { -public: - static PassRefPtr<StylePendingShader> create(CSSShaderValue* value) { return adoptRef(new StylePendingShader(value)); } - - virtual PassRefPtr<CSSValue> cssValue() const { return m_value; } - CSSShaderValue* cssShaderValue() const { return m_value; } -private: - StylePendingShader(CSSShaderValue* value) - : m_value(value) - { - m_isPendingShader = true; - } - - CSSShaderValue* m_value; // Not retained; it owns us. -}; - -} - -#endif // StylePendingShader_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleRareInheritedData.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/StyleRareInheritedData.cpp index 1a1769c787f..741d22d7801 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleRareInheritedData.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleRareInheritedData.cpp @@ -22,7 +22,9 @@ #include "config.h" #include "core/rendering/style/StyleRareInheritedData.h" -#include "core/rendering/style/CursorList.h" +#include "core/rendering/style/AppliedTextDecoration.h" +#include "core/rendering/style/CursorData.h" +#include "core/rendering/style/DataEquivalency.h" #include "core/rendering/style/QuotesData.h" #include "core/rendering/style/RenderStyle.h" #include "core/rendering/style/RenderStyleConstants.h" @@ -37,8 +39,8 @@ struct SameSizeAsStyleRareInheritedData : public RefCounted<SameSizeAsStyleRareI float firstFloat; Color colors[5]; void* ownPtrs[1]; - AtomicString atomicStrings[5]; - void* refPtrs[2]; + AtomicString atomicStrings[4]; + void* refPtrs[3]; Length lengths[1]; float secondFloat; unsigned m_bitfields[2]; @@ -47,8 +49,6 @@ struct SameSizeAsStyleRareInheritedData : public RefCounted<SameSizeAsStyleRareI short hyphenationShorts[3]; Color touchColors; - - void* variableDataRefs[1]; }; COMPILE_ASSERT(sizeof(StyleRareInheritedData) == sizeof(SameSizeAsStyleRareInheritedData), StyleRareInheritedData_should_bit_pack); @@ -62,6 +62,12 @@ StyleRareInheritedData::StyleRareInheritedData() , orphans(RenderStyle::initialOrphans()) , m_hasAutoWidows(true) , m_hasAutoOrphans(true) + , m_textStrokeColorIsCurrentColor(true) + , m_textFillColorIsCurrentColor(true) + , m_textEmphasisColorIsCurrentColor(true) + , m_visitedLinkTextStrokeColorIsCurrentColor(true) + , m_visitedLinkTextFillColorIsCurrentColor(true) + , m_visitedLinkTextEmphasisColorIsCurrentColor(true) , textSecurity(RenderStyle::initialTextSecurity()) , userModify(READ_ONLY) , wordBreak(RenderStyle::initialWordBreak()) @@ -78,33 +84,31 @@ StyleRareInheritedData::StyleRareInheritedData() , m_textJustify(RenderStyle::initialTextJustify()) , m_textOrientation(TextOrientationVerticalRight) , m_textIndentLine(RenderStyle::initialTextIndentLine()) + , m_textIndentType(RenderStyle::initialTextIndentLine()) , m_lineBoxContain(RenderStyle::initialLineBoxContain()) , m_imageRendering(RenderStyle::initialImageRendering()) - , m_lineSnap(RenderStyle::initialLineSnap()) - , m_lineAlign(RenderStyle::initialLineAlign()) , m_textUnderlinePosition(RenderStyle::initialTextUnderlinePosition()) , m_rubyPosition(RenderStyle::initialRubyPosition()) , m_touchActionDelay(RenderStyle::initialTouchActionDelay()) + , m_subtreeWillChangeContents(false) , hyphenationLimitBefore(-1) , hyphenationLimitAfter(-1) , hyphenationLimitLines(-1) - , m_lineGrid(RenderStyle::initialLineGrid()) , m_tabSize(RenderStyle::initialTabSize()) , tapHighlightColor(RenderStyle::initialTapHighlightColor()) { - m_variables.init(); } StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o) : RefCounted<StyleRareInheritedData>() , listStyleImage(o.listStyleImage) - , textStrokeColor(o.textStrokeColor) + , m_textStrokeColor(o.m_textStrokeColor) , textStrokeWidth(o.textStrokeWidth) - , textFillColor(o.textFillColor) - , textEmphasisColor(o.textEmphasisColor) - , visitedLinkTextStrokeColor(o.visitedLinkTextStrokeColor) - , visitedLinkTextFillColor(o.visitedLinkTextFillColor) - , visitedLinkTextEmphasisColor(o.visitedLinkTextEmphasisColor) + , m_textFillColor(o.m_textFillColor) + , m_textEmphasisColor(o.m_textEmphasisColor) + , m_visitedLinkTextStrokeColor(o.m_visitedLinkTextStrokeColor) + , m_visitedLinkTextFillColor(o.m_visitedLinkTextFillColor) + , m_visitedLinkTextEmphasisColor(o.m_visitedLinkTextEmphasisColor) , textShadow(o.textShadow) , highlight(o.highlight) , cursorData(o.cursorData) @@ -114,6 +118,12 @@ StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o) , orphans(o.orphans) , m_hasAutoWidows(o.m_hasAutoWidows) , m_hasAutoOrphans(o.m_hasAutoOrphans) + , m_textStrokeColorIsCurrentColor(o.m_textStrokeColorIsCurrentColor) + , m_textFillColorIsCurrentColor(o.m_textFillColorIsCurrentColor) + , m_textEmphasisColorIsCurrentColor(o.m_textEmphasisColorIsCurrentColor) + , m_visitedLinkTextStrokeColorIsCurrentColor(o.m_visitedLinkTextStrokeColorIsCurrentColor) + , m_visitedLinkTextFillColorIsCurrentColor(o.m_visitedLinkTextFillColorIsCurrentColor) + , m_visitedLinkTextEmphasisColorIsCurrentColor(o.m_visitedLinkTextEmphasisColorIsCurrentColor) , textSecurity(o.textSecurity) , userModify(o.userModify) , wordBreak(o.wordBreak) @@ -130,23 +140,22 @@ StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o) , m_textJustify(o.m_textJustify) , m_textOrientation(o.m_textOrientation) , m_textIndentLine(o.m_textIndentLine) + , m_textIndentType(o.m_textIndentType) , m_lineBoxContain(o.m_lineBoxContain) , m_imageRendering(o.m_imageRendering) - , m_lineSnap(o.m_lineSnap) - , m_lineAlign(o.m_lineAlign) , m_textUnderlinePosition(o.m_textUnderlinePosition) , m_rubyPosition(o.m_rubyPosition) , m_touchActionDelay(o.m_touchActionDelay) + , m_subtreeWillChangeContents(o.m_subtreeWillChangeContents) , hyphenationString(o.hyphenationString) , hyphenationLimitBefore(o.hyphenationLimitBefore) , hyphenationLimitAfter(o.hyphenationLimitAfter) , hyphenationLimitLines(o.hyphenationLimitLines) , locale(o.locale) , textEmphasisCustomMark(o.textEmphasisCustomMark) - , m_lineGrid(o.m_lineGrid) , m_tabSize(o.m_tabSize) , tapHighlightColor(o.tapHighlightColor) - , m_variables(o.m_variables) + , appliedTextDecorations(o.appliedTextDecorations) { } @@ -154,34 +163,31 @@ StyleRareInheritedData::~StyleRareInheritedData() { } -static bool cursorDataEquivalent(const CursorList* c1, const CursorList* c2) -{ - if (c1 == c2) - return true; - if ((!c1 && c2) || (c1 && !c2)) - return false; - return (*c1 == *c2); -} - bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const { - return textStrokeColor == o.textStrokeColor + return m_textStrokeColor == o.m_textStrokeColor && textStrokeWidth == o.textStrokeWidth - && textFillColor == o.textFillColor - && textEmphasisColor == o.textEmphasisColor - && visitedLinkTextStrokeColor == o.visitedLinkTextStrokeColor - && visitedLinkTextFillColor == o.visitedLinkTextFillColor - && visitedLinkTextEmphasisColor == o.visitedLinkTextEmphasisColor + && m_textFillColor == o.m_textFillColor + && m_textEmphasisColor == o.m_textEmphasisColor + && m_visitedLinkTextStrokeColor == o.m_visitedLinkTextStrokeColor + && m_visitedLinkTextFillColor == o.m_visitedLinkTextFillColor + && m_visitedLinkTextEmphasisColor == o.m_visitedLinkTextEmphasisColor && tapHighlightColor == o.tapHighlightColor && shadowDataEquivalent(o) && highlight == o.highlight - && cursorDataEquivalent(cursorData.get(), o.cursorData.get()) + && dataEquivalent(cursorData.get(), o.cursorData.get()) && indent == o.indent && m_effectiveZoom == o.m_effectiveZoom && widows == o.widows && orphans == o.orphans && m_hasAutoWidows == o.m_hasAutoWidows && m_hasAutoOrphans == o.m_hasAutoOrphans + && m_textStrokeColorIsCurrentColor == o.m_textStrokeColorIsCurrentColor + && m_textFillColorIsCurrentColor == o.m_textFillColorIsCurrentColor + && m_textEmphasisColorIsCurrentColor == o.m_textEmphasisColorIsCurrentColor + && m_visitedLinkTextStrokeColorIsCurrentColor == o.m_visitedLinkTextStrokeColorIsCurrentColor + && m_visitedLinkTextFillColorIsCurrentColor == o.m_visitedLinkTextFillColorIsCurrentColor + && m_visitedLinkTextEmphasisColorIsCurrentColor == o.m_visitedLinkTextEmphasisColorIsCurrentColor && textSecurity == o.textSecurity && userModify == o.userModify && wordBreak == o.wordBreak @@ -202,29 +208,29 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const && m_textJustify == o.m_textJustify && m_textOrientation == o.m_textOrientation && m_textIndentLine == o.m_textIndentLine + && m_textIndentType == o.m_textIndentType && m_lineBoxContain == o.m_lineBoxContain + && m_subtreeWillChangeContents == o.m_subtreeWillChangeContents && hyphenationString == o.hyphenationString && locale == o.locale && textEmphasisCustomMark == o.textEmphasisCustomMark - && QuotesData::equals(quotes.get(), o.quotes.get()) + && quotesDataEquivalent(o) && m_tabSize == o.m_tabSize - && m_lineGrid == o.m_lineGrid && m_imageRendering == o.m_imageRendering && m_textUnderlinePosition == o.m_textUnderlinePosition && m_rubyPosition == o.m_rubyPosition - && m_lineSnap == o.m_lineSnap - && m_variables == o.m_variables - && m_lineAlign == o.m_lineAlign - && StyleImage::imagesEquivalent(listStyleImage.get(), o.listStyleImage.get()); + && dataEquivalent(listStyleImage.get(), o.listStyleImage.get()) + && dataEquivalent(appliedTextDecorations, o.appliedTextDecorations); } bool StyleRareInheritedData::shadowDataEquivalent(const StyleRareInheritedData& o) const { - if ((!textShadow && o.textShadow) || (textShadow && !o.textShadow)) - return false; - if (textShadow && o.textShadow && (*textShadow != *o.textShadow)) - return false; - return true; + return dataEquivalent(textShadow.get(), o.textShadow.get()); +} + +bool StyleRareInheritedData::quotesDataEquivalent(const StyleRareInheritedData& o) const +{ + return dataEquivalent(quotes, o.quotes); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleRareInheritedData.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleRareInheritedData.h index 11d3c4b0f52..4dd0ba554a2 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleRareInheritedData.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleRareInheritedData.h @@ -25,21 +25,26 @@ #ifndef StyleRareInheritedData_h #define StyleRareInheritedData_h +#include "core/css/StyleColor.h" #include "core/rendering/style/DataRef.h" -#include "core/rendering/style/StyleVariableData.h" #include "platform/Length.h" #include "platform/graphics/Color.h" #include "wtf/PassRefPtr.h" #include "wtf/RefCounted.h" +#include "wtf/RefVector.h" #include "wtf/text/AtomicString.h" namespace WebCore { -class CursorList; +class AppliedTextDecoration; +class CursorData; class QuotesData; class ShadowList; class StyleImage; +typedef RefVector<AppliedTextDecoration> AppliedTextDecorationList; +typedef RefVector<CursorData> CursorList; + // This struct is for rarely used inherited CSS3, CSS2, and WebKit-specific properties. // By grouping them together, we save space, and only allocate this object when someone // actually uses one of these properties. @@ -55,17 +60,32 @@ public: return !(*this == o); } bool shadowDataEquivalent(const StyleRareInheritedData&) const; + bool quotesDataEquivalent(const StyleRareInheritedData&) const; RefPtr<StyleImage> listStyleImage; - Color textStrokeColor; + StyleColor textStrokeColor() const { return m_textStrokeColorIsCurrentColor ? StyleColor::currentColor() : StyleColor(m_textStrokeColor); } + StyleColor textFillColor() const { return m_textFillColorIsCurrentColor ? StyleColor::currentColor() : StyleColor(m_textFillColor); } + StyleColor textEmphasisColor() const { return m_textEmphasisColorIsCurrentColor ? StyleColor::currentColor() : StyleColor(m_textEmphasisColor); } + StyleColor visitedLinkTextStrokeColor() const { return m_visitedLinkTextStrokeColorIsCurrentColor ? StyleColor::currentColor() : StyleColor(m_visitedLinkTextStrokeColor); } + StyleColor visitedLinkTextFillColor() const { return m_visitedLinkTextFillColorIsCurrentColor ? StyleColor::currentColor() : StyleColor(m_visitedLinkTextFillColor); } + StyleColor visitedLinkTextEmphasisColor() const { return m_visitedLinkTextEmphasisColorIsCurrentColor ? StyleColor::currentColor() : StyleColor(m_visitedLinkTextEmphasisColor); } + + void setTextStrokeColor(const StyleColor& color) { m_textStrokeColor = color.resolve(Color()); m_textStrokeColorIsCurrentColor = color.isCurrentColor(); } + void setTextFillColor(const StyleColor& color) { m_textFillColor = color.resolve(Color()); m_textFillColorIsCurrentColor = color.isCurrentColor(); } + void setTextEmphasisColor(const StyleColor& color) { m_textEmphasisColor = color.resolve(Color()); m_textEmphasisColorIsCurrentColor = color.isCurrentColor(); } + void setVisitedLinkTextStrokeColor(const StyleColor& color) { m_visitedLinkTextStrokeColor = color.resolve(Color()); m_visitedLinkTextStrokeColorIsCurrentColor = color.isCurrentColor(); } + void setVisitedLinkTextFillColor(const StyleColor& color) { m_visitedLinkTextFillColor = color.resolve(Color()); m_visitedLinkTextFillColorIsCurrentColor = color.isCurrentColor(); } + void setVisitedLinkTextEmphasisColor(const StyleColor& color) { m_visitedLinkTextEmphasisColor = color.resolve(Color()); m_visitedLinkTextEmphasisColorIsCurrentColor = color.isCurrentColor(); } + + Color m_textStrokeColor; float textStrokeWidth; - Color textFillColor; - Color textEmphasisColor; + Color m_textFillColor; + Color m_textEmphasisColor; - Color visitedLinkTextStrokeColor; - Color visitedLinkTextFillColor; - Color visitedLinkTextEmphasisColor; + Color m_visitedLinkTextStrokeColor; + Color m_visitedLinkTextFillColor; + Color m_visitedLinkTextEmphasisColor; RefPtr<ShadowList> textShadow; // Our text shadow information for shadowed text drawing. AtomicString highlight; // Apple-specific extension for custom highlight rendering. @@ -80,6 +100,13 @@ public: unsigned m_hasAutoWidows : 1; unsigned m_hasAutoOrphans : 1; + unsigned m_textStrokeColorIsCurrentColor : 1; + unsigned m_textFillColorIsCurrentColor : 1; + unsigned m_textEmphasisColorIsCurrentColor : 1; + unsigned m_visitedLinkTextStrokeColorIsCurrentColor : 1; + unsigned m_visitedLinkTextFillColorIsCurrentColor : 1; + unsigned m_visitedLinkTextEmphasisColorIsCurrentColor : 1; + unsigned textSecurity : 2; // ETextSecurity unsigned userModify : 2; // EUserModify (editing) unsigned wordBreak : 2; // EWordBreak @@ -96,15 +123,18 @@ public: unsigned m_textJustify : 2; // TextJustify unsigned m_textOrientation : 2; // TextOrientation unsigned m_textIndentLine : 1; // TextIndentEachLine + unsigned m_textIndentType : 1; // TextIndentHanging unsigned m_lineBoxContain: 7; // LineBoxContain // CSS Image Values Level 3 unsigned m_imageRendering : 2; // EImageRendering - unsigned m_lineSnap : 2; // LineSnap - unsigned m_lineAlign : 1; // LineAlign unsigned m_textUnderlinePosition : 2; // TextUnderlinePosition unsigned m_rubyPosition : 1; // RubyPosition unsigned m_touchActionDelay : 1; // TouchActionDelay + // Though will-change is not itself an inherited property, the intent + // expressed by 'will-change: contents' includes descendants. + unsigned m_subtreeWillChangeContents : 1; + AtomicString hyphenationString; short hyphenationLimitBefore; short hyphenationLimitAfter; @@ -115,12 +145,11 @@ public: AtomicString textEmphasisCustomMark; RefPtr<QuotesData> quotes; - AtomicString m_lineGrid; unsigned m_tabSize; Color tapHighlightColor; - DataRef<StyleVariableData> m_variables; + RefPtr<AppliedTextDecorationList> appliedTextDecorations; private: StyleRareInheritedData(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleRareNonInheritedData.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/StyleRareNonInheritedData.cpp index 2d312788ec6..165edc705a4 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleRareNonInheritedData.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleRareNonInheritedData.cpp @@ -23,6 +23,7 @@ #include "core/rendering/style/StyleRareNonInheritedData.h" #include "core/rendering/style/ContentData.h" +#include "core/rendering/style/DataEquivalency.h" #include "core/rendering/style/RenderStyle.h" #include "core/rendering/style/ShadowList.h" #include "core/rendering/style/StyleFilterData.h" @@ -42,27 +43,28 @@ StyleRareNonInheritedData::StyleRareNonInheritedData() , m_draggableRegionMode(DraggableRegionNone) , m_mask(MaskFillLayer, true) , m_pageSize() - , m_shapeInside(RenderStyle::initialShapeInside()) , m_shapeOutside(RenderStyle::initialShapeOutside()) , m_shapeMargin(RenderStyle::initialShapeMargin()) - , m_shapePadding(RenderStyle::initialShapePadding()) , m_shapeImageThreshold(RenderStyle::initialShapeImageThreshold()) , m_clipPath(RenderStyle::initialClipPath()) + , m_textDecorationColor(StyleColor::currentColor()) + , m_visitedLinkTextDecorationColor(StyleColor::currentColor()) , m_visitedLinkBackgroundColor(RenderStyle::initialBackgroundColor()) + , m_visitedLinkOutlineColor(StyleColor::currentColor()) + , m_visitedLinkBorderLeftColor(StyleColor::currentColor()) + , m_visitedLinkBorderRightColor(StyleColor::currentColor()) + , m_visitedLinkBorderTopColor(StyleColor::currentColor()) + , m_visitedLinkBorderBottomColor(StyleColor::currentColor()) , m_order(RenderStyle::initialOrder()) , m_objectPosition(RenderStyle::initialObjectPosition()) - , m_flowThread(RenderStyle::initialFlowThread()) - , m_regionThread(RenderStyle::initialRegionThread()) - , m_regionFragment(RenderStyle::initialRegionFragment()) - , m_regionBreakAfter(RenderStyle::initialPageBreak()) - , m_regionBreakBefore(RenderStyle::initialPageBreak()) - , m_regionBreakInside(RenderStyle::initialPageBreak()) , m_pageSizeType(PAGE_SIZE_AUTO) , m_transformStyle3D(RenderStyle::initialTransformStyle3D()) , m_backfaceVisibility(RenderStyle::initialBackfaceVisibility()) , m_alignContent(RenderStyle::initialAlignContent()) , m_alignItems(RenderStyle::initialAlignItems()) + , m_alignItemsOverflowAlignment(RenderStyle::initialAlignItemsOverflowAlignment()) , m_alignSelf(RenderStyle::initialAlignSelf()) + , m_alignSelfOverflowAlignment(RenderStyle::initialAlignSelfOverflowAlignment()) , m_justifyContent(RenderStyle::initialJustifyContent()) , userDrag(RenderStyle::initialUserDrag()) , textOverflow(RenderStyle::initialTextOverflow()) @@ -74,12 +76,21 @@ StyleRareNonInheritedData::StyleRareNonInheritedData() , m_textDecorationStyle(RenderStyle::initialTextDecorationStyle()) , m_wrapFlow(RenderStyle::initialWrapFlow()) , m_wrapThrough(RenderStyle::initialWrapThrough()) - , m_runningAcceleratedAnimation(false) + , m_hasCurrentOpacityAnimation(false) + , m_hasCurrentTransformAnimation(false) + , m_hasCurrentFilterAnimation(false) + , m_runningOpacityAnimationOnCompositor(false) + , m_runningTransformAnimationOnCompositor(false) + , m_runningFilterAnimationOnCompositor(false) , m_hasAspectRatio(false) , m_effectiveBlendMode(RenderStyle::initialBlendMode()) , m_touchAction(RenderStyle::initialTouchAction()) , m_objectFit(RenderStyle::initialObjectFit()) , m_isolation(RenderStyle::initialIsolation()) + , m_justifySelf(RenderStyle::initialJustifySelf()) + , m_justifySelfOverflowAlignment(RenderStyle::initialJustifySelfOverflowAlignment()) + , m_scrollBehavior(RenderStyle::initialScrollBehavior()) + , m_requiresAcceleratedCompositingForExternalReasons(false) { m_maskBoxImage.setMaskDefaults(); } @@ -99,6 +110,7 @@ StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonInherited , m_marquee(o.m_marquee) , m_multiCol(o.m_multiCol) , m_transform(o.m_transform) + , m_willChange(o.m_willChange) , m_filter(o.m_filter) , m_grid(o.m_grid) , m_gridItem(o.m_gridItem) @@ -106,15 +118,13 @@ StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonInherited , m_counterDirectives(o.m_counterDirectives ? clone(*o.m_counterDirectives) : nullptr) , m_boxShadow(o.m_boxShadow) , m_boxReflect(o.m_boxReflect) - , m_animations(o.m_animations ? adoptPtr(new CSSAnimationDataList(*o.m_animations)) : nullptr) - , m_transitions(o.m_transitions ? adoptPtr(new CSSAnimationDataList(*o.m_transitions)) : nullptr) + , m_animations(o.m_animations ? CSSAnimationData::create(*o.m_animations) : nullptr) + , m_transitions(o.m_transitions ? CSSTransitionData::create(*o.m_transitions) : nullptr) , m_mask(o.m_mask) , m_maskBoxImage(o.m_maskBoxImage) , m_pageSize(o.m_pageSize) - , m_shapeInside(o.m_shapeInside) , m_shapeOutside(o.m_shapeOutside) , m_shapeMargin(o.m_shapeMargin) - , m_shapePadding(o.m_shapePadding) , m_shapeImageThreshold(o.m_shapeImageThreshold) , m_clipPath(o.m_clipPath) , m_textDecorationColor(o.m_textDecorationColor) @@ -127,18 +137,14 @@ StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonInherited , m_visitedLinkBorderBottomColor(o.m_visitedLinkBorderBottomColor) , m_order(o.m_order) , m_objectPosition(o.m_objectPosition) - , m_flowThread(o.m_flowThread) - , m_regionThread(o.m_regionThread) - , m_regionFragment(o.m_regionFragment) - , m_regionBreakAfter(o.m_regionBreakAfter) - , m_regionBreakBefore(o.m_regionBreakBefore) - , m_regionBreakInside(o.m_regionBreakInside) , m_pageSizeType(o.m_pageSizeType) , m_transformStyle3D(o.m_transformStyle3D) , m_backfaceVisibility(o.m_backfaceVisibility) , m_alignContent(o.m_alignContent) , m_alignItems(o.m_alignItems) + , m_alignItemsOverflowAlignment(o.m_alignItemsOverflowAlignment) , m_alignSelf(o.m_alignSelf) + , m_alignSelfOverflowAlignment(o.m_alignSelfOverflowAlignment) , m_justifyContent(o.m_justifyContent) , userDrag(o.userDrag) , textOverflow(o.textOverflow) @@ -150,12 +156,21 @@ StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonInherited , m_textDecorationStyle(o.m_textDecorationStyle) , m_wrapFlow(o.m_wrapFlow) , m_wrapThrough(o.m_wrapThrough) - , m_runningAcceleratedAnimation(o.m_runningAcceleratedAnimation) + , m_hasCurrentOpacityAnimation(o.m_hasCurrentOpacityAnimation) + , m_hasCurrentTransformAnimation(o.m_hasCurrentTransformAnimation) + , m_hasCurrentFilterAnimation(o.m_hasCurrentFilterAnimation) + , m_runningOpacityAnimationOnCompositor(o.m_runningOpacityAnimationOnCompositor) + , m_runningTransformAnimationOnCompositor(o.m_runningTransformAnimationOnCompositor) + , m_runningFilterAnimationOnCompositor(o.m_runningFilterAnimationOnCompositor) , m_hasAspectRatio(o.m_hasAspectRatio) , m_effectiveBlendMode(o.m_effectiveBlendMode) , m_touchAction(o.m_touchAction) , m_objectFit(o.m_objectFit) , m_isolation(o.m_isolation) + , m_justifySelf(o.m_justifySelf) + , m_justifySelfOverflowAlignment(o.m_justifySelfOverflowAlignment) + , m_scrollBehavior(o.m_scrollBehavior) + , m_requiresAcceleratedCompositingForExternalReasons(o.m_requiresAcceleratedCompositingForExternalReasons) { } @@ -181,6 +196,7 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c && m_marquee == o.m_marquee && m_multiCol == o.m_multiCol && m_transform == o.m_transform + && m_willChange == o.m_willChange && m_filter == o.m_filter && m_grid == o.m_grid && m_gridItem == o.m_gridItem @@ -193,10 +209,8 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c && m_mask == o.m_mask && m_maskBoxImage == o.m_maskBoxImage && m_pageSize == o.m_pageSize - && m_shapeInside == o.m_shapeInside && m_shapeOutside == o.m_shapeOutside && m_shapeMargin == o.m_shapeMargin - && m_shapePadding == o.m_shapePadding && m_shapeImageThreshold == o.m_shapeImageThreshold && m_clipPath == o.m_clipPath && m_textDecorationColor == o.m_textDecorationColor @@ -210,18 +224,14 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c && m_order == o.m_order && m_objectPosition == o.m_objectPosition && m_callbackSelectors == o.m_callbackSelectors - && m_flowThread == o.m_flowThread - && m_regionThread == o.m_regionThread - && m_regionFragment == o.m_regionFragment - && m_regionBreakAfter == o.m_regionBreakAfter - && m_regionBreakBefore == o.m_regionBreakBefore - && m_regionBreakInside == o.m_regionBreakInside && m_pageSizeType == o.m_pageSizeType && m_transformStyle3D == o.m_transformStyle3D && m_backfaceVisibility == o.m_backfaceVisibility && m_alignContent == o.m_alignContent && m_alignItems == o.m_alignItems + && m_alignItemsOverflowAlignment == o.m_alignItemsOverflowAlignment && m_alignSelf == o.m_alignSelf + && m_alignSelfOverflowAlignment == o.m_alignSelfOverflowAlignment && m_justifyContent == o.m_justifyContent && userDrag == o.userDrag && textOverflow == o.textOverflow @@ -233,12 +243,18 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c && m_textDecorationStyle == o.m_textDecorationStyle && m_wrapFlow == o.m_wrapFlow && m_wrapThrough == o.m_wrapThrough - && !m_runningAcceleratedAnimation && !o.m_runningAcceleratedAnimation + && m_hasCurrentOpacityAnimation == o.m_hasCurrentOpacityAnimation + && m_hasCurrentTransformAnimation == o.m_hasCurrentTransformAnimation + && m_hasCurrentFilterAnimation == o.m_hasCurrentFilterAnimation && m_effectiveBlendMode == o.m_effectiveBlendMode && m_hasAspectRatio == o.m_hasAspectRatio && m_touchAction == o.m_touchAction && m_objectFit == o.m_objectFit - && m_isolation == o.m_isolation; + && m_isolation == o.m_isolation + && m_justifySelf == o.m_justifySelf + && m_justifySelfOverflowAlignment == o.m_justifySelfOverflowAlignment + && m_scrollBehavior == o.m_scrollBehavior + && m_requiresAcceleratedCompositingForExternalReasons == o.m_requiresAcceleratedCompositingForExternalReasons; } bool StyleRareNonInheritedData::contentDataEquivalent(const StyleRareNonInheritedData& o) const @@ -256,50 +272,35 @@ bool StyleRareNonInheritedData::contentDataEquivalent(const StyleRareNonInherite bool StyleRareNonInheritedData::counterDataEquivalent(const StyleRareNonInheritedData& o) const { - if (m_counterDirectives.get() == o.m_counterDirectives.get()) - return true; - - if (m_counterDirectives && o.m_counterDirectives && *m_counterDirectives == *o.m_counterDirectives) - return true; - - return false; + return dataEquivalent(m_counterDirectives, o.m_counterDirectives); } bool StyleRareNonInheritedData::shadowDataEquivalent(const StyleRareNonInheritedData& o) const { - if ((!m_boxShadow && o.m_boxShadow) || (m_boxShadow && !o.m_boxShadow)) - return false; - if (m_boxShadow && o.m_boxShadow && (*m_boxShadow != *o.m_boxShadow)) - return false; - return true; + return dataEquivalent(m_boxShadow, o.m_boxShadow); } bool StyleRareNonInheritedData::reflectionDataEquivalent(const StyleRareNonInheritedData& o) const { - if (m_boxReflect != o.m_boxReflect) { - if (!m_boxReflect || !o.m_boxReflect) - return false; - return *m_boxReflect == *o.m_boxReflect; - } - return true; + return dataEquivalent(m_boxReflect, o.m_boxReflect); } bool StyleRareNonInheritedData::animationDataEquivalent(const StyleRareNonInheritedData& o) const { - if ((!m_animations && o.m_animations) || (m_animations && !o.m_animations)) - return false; - if (m_animations && o.m_animations && (*m_animations != *o.m_animations)) + if (!m_animations && !o.m_animations) + return true; + if (!m_animations || !o.m_animations) return false; - return true; + return m_animations->animationsMatchForStyleRecalc(*o.m_animations); } bool StyleRareNonInheritedData::transitionDataEquivalent(const StyleRareNonInheritedData& o) const { - if ((!m_transitions && o.m_transitions) || (m_transitions && !o.m_transitions)) - return false; - if (m_transitions && o.m_transitions && (*m_transitions != *o.m_transitions)) + if (!m_transitions && !o.m_transitions) + return true; + if (!m_transitions || !o.m_transitions) return false; - return true; + return m_transitions->transitionsMatchForStyleRecalc(*o.m_transitions); } bool StyleRareNonInheritedData::hasFilters() const diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleRareNonInheritedData.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleRareNonInheritedData.h index 9ce04870219..f23461abab3 100755..100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleRareNonInheritedData.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleRareNonInheritedData.h @@ -25,6 +25,7 @@ #ifndef StyleRareNonInheritedData_h #define StyleRareNonInheritedData_h +#include "core/css/StyleColor.h" #include "core/rendering/ClipPathOperation.h" #include "core/rendering/style/BasicShapes.h" #include "core/rendering/style/CounterDirectives.h" @@ -43,7 +44,9 @@ namespace WebCore { class ContentData; -class CSSAnimationDataList; +class CSSAnimationData; +class CSSTransitionData; +class LengthSize; class ShadowList; class StyleDeprecatedFlexibleBoxData; class StyleFilterData; @@ -53,10 +56,8 @@ class StyleGridItemData; class StyleMarqueeData; class StyleMultiColData; class StyleReflection; -class StyleResolver; class StyleTransformData; - -struct LengthSize; +class StyleWillChangeData; // Page size type. // StyleRareNonInheritedData::m_pageSize is meaningful only when @@ -106,6 +107,7 @@ public: DataRef<StyleMarqueeData> m_marquee; // Marquee properties DataRef<StyleMultiColData> m_multiCol; // CSS3 multicol properties DataRef<StyleTransformData> m_transform; // Transform properties (rotate, scale, skew, etc.) + DataRef<StyleWillChangeData> m_willChange; // CSS Will Change DataRef<StyleFilterData> m_filter; // Filter operations (url, sepia, blur, etc.) @@ -119,30 +121,28 @@ public: RefPtr<StyleReflection> m_boxReflect; - OwnPtr<CSSAnimationDataList> m_animations; - OwnPtr<CSSAnimationDataList> m_transitions; + OwnPtrWillBePersistent<CSSAnimationData> m_animations; + OwnPtrWillBePersistent<CSSTransitionData> m_transitions; FillLayer m_mask; NinePieceImage m_maskBoxImage; LengthSize m_pageSize; - RefPtr<ShapeValue> m_shapeInside; RefPtr<ShapeValue> m_shapeOutside; Length m_shapeMargin; - Length m_shapePadding; float m_shapeImageThreshold; RefPtr<ClipPathOperation> m_clipPath; - Color m_textDecorationColor; - Color m_visitedLinkTextDecorationColor; - Color m_visitedLinkBackgroundColor; - Color m_visitedLinkOutlineColor; - Color m_visitedLinkBorderLeftColor; - Color m_visitedLinkBorderRightColor; - Color m_visitedLinkBorderTopColor; - Color m_visitedLinkBorderBottomColor; + StyleColor m_textDecorationColor; + StyleColor m_visitedLinkTextDecorationColor; + StyleColor m_visitedLinkBackgroundColor; + StyleColor m_visitedLinkOutlineColor; + StyleColor m_visitedLinkBorderLeftColor; + StyleColor m_visitedLinkBorderRightColor; + StyleColor m_visitedLinkBorderTopColor; + StyleColor m_visitedLinkBorderBottomColor; int m_order; @@ -150,21 +150,15 @@ public: Vector<String> m_callbackSelectors; - AtomicString m_flowThread; - AtomicString m_regionThread; - unsigned m_regionFragment : 1; // RegionFragment - - unsigned m_regionBreakAfter : 2; // EPageBreak - unsigned m_regionBreakBefore : 2; // EPageBreak - unsigned m_regionBreakInside : 2; // EPageBreak - unsigned m_pageSizeType : 2; // PageSizeType unsigned m_transformStyle3D : 1; // ETransformStyle3D unsigned m_backfaceVisibility : 1; // EBackfaceVisibility unsigned m_alignContent : 3; // EAlignContent - unsigned m_alignItems : 3; // EAlignItems - unsigned m_alignSelf : 3; // EAlignItems + unsigned m_alignItems : 4; // ItemPosition + unsigned m_alignItemsOverflowAlignment : 2; // OverflowAlignment + unsigned m_alignSelf : 4; // ItemPosition + unsigned m_alignSelfOverflowAlignment : 2; // OverflowAlignment unsigned m_justifyContent : 3; // EJustifyContent unsigned userDrag : 2; // EUserDrag @@ -179,7 +173,12 @@ public: unsigned m_wrapFlow: 3; // WrapFlow unsigned m_wrapThrough: 1; // WrapThrough - unsigned m_runningAcceleratedAnimation : 1; + unsigned m_hasCurrentOpacityAnimation : 1; + unsigned m_hasCurrentTransformAnimation : 1; + unsigned m_hasCurrentFilterAnimation : 1; + unsigned m_runningOpacityAnimationOnCompositor : 1; + unsigned m_runningTransformAnimationOnCompositor : 1; + unsigned m_runningFilterAnimationOnCompositor : 1; unsigned m_hasAspectRatio : 1; // Whether or not an aspect ratio has been specified. @@ -191,6 +190,19 @@ public: unsigned m_isolation : 1; // Isolation + unsigned m_justifySelf : 4; // ItemPosition + unsigned m_justifySelfOverflowAlignment : 2; // OverflowAlignment + + // ScrollBehavior. 'scroll-behavior' has 2 accepted values, but ScrollBehavior has a third + // value (that can only be specified using CSSOM scroll APIs) so 2 bits are needed. + unsigned m_scrollBehavior: 2; + + // Plugins require accelerated compositing for reasons external to blink. + // In which case, we need to update the RenderStyle on the RenderEmbeddedObject, + // so store this bit so that the style actually changes when the plugin + // becomes composited. + unsigned m_requiresAcceleratedCompositingForExternalReasons: 1; + private: StyleRareNonInheritedData(); StyleRareNonInheritedData(const StyleRareNonInheritedData&); diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleShader.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleShader.h deleted file mode 100644 index c5927e67591..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleShader.h +++ /dev/null @@ -1,64 +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 StyleShader_h -#define StyleShader_h - -#include "wtf/RefCounted.h" - -namespace WebCore { - -class ShaderResource; -class CSSValue; - -class StyleShader : public RefCounted<StyleShader> { -public: - virtual ~StyleShader() { } - - ALWAYS_INLINE bool isShaderResource() const { return m_isShaderResource; } - ALWAYS_INLINE bool isPendingShader() const { return m_isPendingShader; } - - virtual PassRefPtr<CSSValue> cssValue() const = 0; - - virtual ShaderResource* resource() const { return 0; } - -protected: - StyleShader() - : m_isShaderResource(false) - , m_isPendingShader(false) - { - } - bool m_isShaderResource : 1; - bool m_isPendingShader : 1; -}; - -} - - -#endif // StyleShader_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleVariableData.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleVariableData.h deleted file mode 100644 index 23429f19c2e..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleVariableData.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT - * OWNER 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 StyleVariableData_h -#define StyleVariableData_h - -#include "wtf/Forward.h" -#include "wtf/HashMap.h" -#include "wtf/RefCounted.h" -#include "wtf/text/AtomicStringHash.h" - -namespace WebCore { - -class CursorList; -class QuotesData; -class ShadowData; - -class StyleVariableData : public RefCounted<StyleVariableData> { -public: - static PassRefPtr<StyleVariableData> create() { return adoptRef(new StyleVariableData()); } - PassRefPtr<StyleVariableData> copy() const { return adoptRef(new StyleVariableData(*this)); } - - bool operator==(const StyleVariableData& other) const { return other.m_data == m_data; } - bool operator!=(const StyleVariableData& other) const { return !(*this == other); } - - void setVariable(const AtomicString& name, const String& value) { m_data.set(name, value); } - - HashMap<AtomicString, String> m_data; -private: - explicit StyleVariableData() : RefCounted<StyleVariableData>() { } - StyleVariableData(const StyleVariableData& other) : RefCounted<StyleVariableData>(), m_data(HashMap<AtomicString, String>(other.m_data)) { } -}; - -} // namespace WebCore - -#endif /* StyleVariableData_h */ diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleVisualData.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/StyleVisualData.cpp index db87122431b..e2774374bef 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleVisualData.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleVisualData.cpp @@ -29,7 +29,6 @@ namespace WebCore { StyleVisualData::StyleVisualData() : hasClip(false) , textDecoration(RenderStyle::initialTextDecoration()) - , m_textAutosizingMultiplier(1) , m_zoom(RenderStyle::initialZoom()) { } @@ -43,7 +42,6 @@ StyleVisualData::StyleVisualData(const StyleVisualData& o) , clip(o.clip) , hasClip(o.hasClip) , textDecoration(o.textDecoration) - , m_textAutosizingMultiplier(o.m_textAutosizingMultiplier) , m_zoom(RenderStyle::initialZoom()) { } diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleVisualData.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleVisualData.h index 2657b93ceec..ed79ea1aece 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/style/StyleVisualData.h +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleVisualData.h @@ -43,7 +43,6 @@ public: return clip == o.clip && hasClip == o.hasClip && textDecoration == o.textDecoration - && m_textAutosizingMultiplier == o.m_textAutosizingMultiplier && m_zoom == o.m_zoom; } bool operator!=(const StyleVisualData& o) const { return !(*this == o); } @@ -52,7 +51,6 @@ public: bool hasClip : 1; unsigned textDecoration : TextDecorationBits; // Text decorations defined *only* by this element. - float m_textAutosizingMultiplier; float m_zoom; private: diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleWillChangeData.cpp b/chromium/third_party/WebKit/Source/core/rendering/style/StyleWillChangeData.cpp new file mode 100644 index 00000000000..7cd2bcbf0aa --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleWillChangeData.cpp @@ -0,0 +1,24 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" +#include "core/rendering/style/StyleWillChangeData.h" + +namespace WebCore { + +StyleWillChangeData::StyleWillChangeData() + : m_contents(false) + , m_scrollPosition(false) +{ +} + +StyleWillChangeData::StyleWillChangeData(const StyleWillChangeData& o) + : RefCounted<StyleWillChangeData>() + , m_properties(o.m_properties) + , m_contents(o.m_contents) + , m_scrollPosition(o.m_scrollPosition) +{ +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/style/StyleWillChangeData.h b/chromium/third_party/WebKit/Source/core/rendering/style/StyleWillChangeData.h new file mode 100644 index 00000000000..9a9b6e76212 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/rendering/style/StyleWillChangeData.h @@ -0,0 +1,42 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef StyleWillChangeData_h +#define StyleWillChangeData_h + +#include "core/CSSPropertyNames.h" +#include "core/CSSValueKeywords.h" +#include "wtf/PassRefPtr.h" +#include "wtf/RefCounted.h" +#include "wtf/Vector.h" + +namespace WebCore { + +class StyleWillChangeData : public RefCounted<StyleWillChangeData> { +public: + static PassRefPtr<StyleWillChangeData> create() { return adoptRef(new StyleWillChangeData); } + PassRefPtr<StyleWillChangeData> copy() const { return adoptRef(new StyleWillChangeData(*this)); } + + bool operator==(const StyleWillChangeData& o) const + { + return m_properties == o.m_properties && m_contents == o.m_contents && m_scrollPosition == o.m_scrollPosition; + } + + bool operator!=(const StyleWillChangeData& o) const + { + return !(*this == o); + } + + Vector<CSSPropertyID> m_properties; + unsigned m_contents : 1; + unsigned m_scrollPosition : 1; + +private: + StyleWillChangeData(); + StyleWillChangeData(const StyleWillChangeData&); +}; + +} // namespace WebCore + +#endif // StyleWillChangeData_h diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/ReferenceFilterBuilder.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/ReferenceFilterBuilder.cpp index 8c0a5c517a4..a53a3dcf118 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/ReferenceFilterBuilder.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/ReferenceFilterBuilder.cpp @@ -29,9 +29,9 @@ #include "core/rendering/svg/ReferenceFilterBuilder.h" -#include "SVGNames.h" #include "core/css/CSSPrimitiveValue.h" #include "core/css/CSSPrimitiveValueMappings.h" +#include "core/css/StylePropertySet.h" #include "core/dom/Element.h" #include "core/fetch/DocumentResource.h" #include "core/rendering/svg/RenderSVGResourceFilter.h" @@ -80,10 +80,11 @@ static bool getSVGElementColorSpace(SVGElement* svgElement, ColorSpace& cs) if (svgStyle) { // If a layout has been performed, then we can use the fast path to get this attribute eColorInterpolation = svgStyle->colorInterpolationFilters(); + } else if (!svgElement->presentationAttributeStyle()) { + return false; } else { // Otherwise, use the slow path by using string comparison (used by external svg files) - RefPtr<CSSValue> cssValue = svgElement->getPresentationAttribute( - SVGNames::color_interpolation_filtersAttr.toString()); + RefPtrWillBeRawPtr<CSSValue> cssValue = svgElement->presentationAttributeStyle()->getPropertyCSSValue(CSSPropertyColorInterpolationFilters); if (cssValue.get() && cssValue->isPrimitiveValue()) { const CSSPrimitiveValue& primitiveValue = *((CSSPrimitiveValue*)cssValue.get()); eColorInterpolation = (EColorInterpolation)primitiveValue; @@ -110,9 +111,9 @@ static bool getSVGElementColorSpace(SVGElement* svgElement, ColorSpace& cs) PassRefPtr<FilterEffect> ReferenceFilterBuilder::build(Filter* parentFilter, RenderObject* renderer, FilterEffect* previousEffect, const ReferenceFilterOperation* filterOperation) { if (!renderer) - return 0; + return nullptr; - Document* document = &renderer->document(); + TreeScope* treeScope = &renderer->node()->treeScope(); if (DocumentResourceReference* documentResourceRef = documentResourceReference(filterOperation)) { DocumentResource* cachedSVGDocument = documentResourceRef->document(); @@ -120,25 +121,25 @@ PassRefPtr<FilterEffect> ReferenceFilterBuilder::build(Filter* parentFilter, Ren // If we have an SVG document, this is an external reference. Otherwise // we look up the referenced node in the current document. if (cachedSVGDocument) - document = cachedSVGDocument->document(); + treeScope = cachedSVGDocument->document(); } - if (!document) - return 0; + if (!treeScope) + return nullptr; - Element* filter = document->getElementById(filterOperation->fragment()); + Element* filter = treeScope->getElementById(filterOperation->fragment()); if (!filter) { // Although we did not find the referenced filter, it might exist later - // in the document - document->accessSVGExtensions()->addPendingResource(filterOperation->fragment(), toElement(renderer->node())); - return 0; + // in the document. + treeScope->document().accessSVGExtensions().addPendingResource(filterOperation->fragment(), toElement(renderer->node())); + return nullptr; } - if (!filter->isSVGElement() || !filter->hasTagName(SVGNames::filterTag)) - return 0; + if (!isSVGFilterElement(*filter)) + return nullptr; - SVGFilterElement* filterElement = toSVGFilterElement(toSVGElement(filter)); + SVGFilterElement& filterElement = toSVGFilterElement(*filter); // FIXME: Figure out what to do with SourceAlpha. Right now, we're // using the alpha of the original input layer, which is obviously @@ -148,13 +149,9 @@ PassRefPtr<FilterEffect> ReferenceFilterBuilder::build(Filter* parentFilter, Ren RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(previousEffect, SourceAlpha::create(parentFilter)); ColorSpace filterColorSpace = ColorSpaceDeviceRGB; - bool useFilterColorSpace = getSVGElementColorSpace(filterElement, filterColorSpace); - - for (Node* node = filterElement->firstChild(); node; node = node->nextSibling()) { - if (!node->isSVGElement()) - continue; + bool useFilterColorSpace = getSVGElementColorSpace(&filterElement, filterColorSpace); - SVGElement* element = toSVGElement(node); + for (SVGElement* element = Traversal<SVGElement>::firstChild(filterElement); element; element = Traversal<SVGElement>::nextSibling(*element)) { if (!element->isFilterEffect()) continue; @@ -165,11 +162,11 @@ PassRefPtr<FilterEffect> ReferenceFilterBuilder::build(Filter* parentFilter, Ren continue; effectElement->setStandardAttributes(effect.get()); - effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnitsCurrentValue(), parentFilter->sourceImageRect())); + effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement.primitiveUnits()->currentValue()->enumValue(), parentFilter->sourceImageRect())); ColorSpace colorSpace = filterColorSpace; if (useFilterColorSpace || getSVGElementColorSpace(effectElement, colorSpace)) effect->setOperatingColorSpace(colorSpace); - builder->add(effectElement->resultCurrentValue(), effect); + builder->add(AtomicString(effectElement->result()->currentValue()->value()), effect); } return builder->lastEffect(); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGBlock.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGBlock.cpp index ab40394a4b3..8eddc1f1e6f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGBlock.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGBlock.cpp @@ -23,7 +23,9 @@ #include "core/rendering/svg/RenderSVGBlock.h" +#include "core/rendering/RenderView.h" #include "core/rendering/style/ShadowList.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGResourcesCache.h" #include "core/svg/SVGElement.h" @@ -50,7 +52,7 @@ void RenderSVGBlock::updateFromStyle() // RenderSVGlock, used by Render(SVGText|ForeignObject), is not allowed to call setHasOverflowClip(true). // RenderBlock assumes a layer to be present when the overflow clip functionality is requested. Both - // Render(SVGText|ForeignObject) return 'false' on 'requiresLayer'. Fine for RenderSVGText. + // Render(SVGText|ForeignObject) return 'NoLayer' on 'layerTypeRequired'. Fine for RenderSVGText. // // If we want to support overflow rules for <foreignObject> we can choose between two solutions: // a) make RenderSVGForeignObject require layers and SVG layer aware @@ -77,11 +79,46 @@ void RenderSVGBlock::willBeDestroyed() void RenderSVGBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - if (diff == StyleDifferenceLayout) + if (diff.needsFullLayout()) setNeedsBoundariesUpdate(); RenderBlock::styleDidChange(diff, oldStyle); SVGResourcesCache::clientStyleChanged(this, diff, style()); } +void RenderSVGBlock::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const +{ + SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed); +} + +const RenderObject* RenderSVGBlock::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const +{ + return SVGRenderSupport::pushMappingToContainer(this, ancestorToStopAt, geometryMap); +} + +LayoutRect RenderSVGBlock::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const +{ + return SVGRenderSupport::clippedOverflowRectForRepaint(this, paintInvalidationContainer); +} + +void RenderSVGBlock::computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect& paintInvalidationRect, bool fixed) const +{ + SVGRenderSupport::computeFloatRectForRepaint(this, paintInvalidationContainer, paintInvalidationRect, fixed); +} + +bool RenderSVGBlock::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint&, HitTestAction) +{ + ASSERT_NOT_REACHED(); + return false; +} + +void RenderSVGBlock::invalidateTreeAfterLayout(const RenderLayerModelObject& paintInvalidationContainer) +{ + if (!shouldCheckForPaintInvalidationAfterLayout()) + return; + + ForceHorriblySlowRectMapping slowRectMapping(*this); + RenderBlockFlow::invalidateTreeAfterLayout(paintInvalidationContainer); +} + } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGBlock.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGBlock.h index 6f08eb1f72f..1e21c7c639a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGBlock.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGBlock.h @@ -32,19 +32,33 @@ public: virtual LayoutRect visualOverflowRect() const OVERRIDE FINAL; + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const OVERRIDE FINAL; + virtual void computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect&, bool fixed = false) const OVERRIDE FINAL; + + virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE FINAL; + virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE FINAL; + + virtual AffineTransform localTransform() const OVERRIDE FINAL { return m_localTransform; } + + virtual LayerType layerTypeRequired() const OVERRIDE FINAL { return NoLayer; } + + virtual void invalidateTreeAfterLayout(const RenderLayerModelObject&) OVERRIDE; + protected: virtual void willBeDestroyed() OVERRIDE; + AffineTransform m_localTransform; + private: virtual void updateFromStyle() OVERRIDE FINAL; - virtual bool isRenderSVGBlock() const OVERRIDE FINAL { return true; }; - - virtual bool supportsPartialLayout() const OVERRIDE { return false; } + virtual bool isSVG() const OVERRIDE FINAL { return true; } virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const OVERRIDE FINAL; virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE FINAL; + + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; }; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGContainer.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGContainer.cpp index 04f28cae872..5767807922e 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGContainer.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGContainer.cpp @@ -25,13 +25,15 @@ #include "core/rendering/svg/RenderSVGContainer.h" +#include "core/frame/Settings.h" #include "core/rendering/GraphicsContextAnnotator.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/LayoutRepainter.h" #include "core/rendering/RenderView.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGRenderingContext.h" #include "core/rendering/svg/SVGResources.h" #include "core/rendering/svg/SVGResourcesCache.h" +#include "platform/graphics/GraphicsContextCullSaver.h" #include "platform/graphics/GraphicsContextStateSaver.h" namespace WebCore { @@ -52,9 +54,8 @@ void RenderSVGContainer::layout() ASSERT(needsLayout()); // RenderSVGRoot disables layoutState for the SVG rendering tree. - ASSERT(!view()->layoutStateEnabled()); + ASSERT(!view()->layoutStateCachedOffsetsEnabled()); - LayoutRectRecorder recorder(*this); LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(this) || selfWillPaint()); // Allow RenderSVGViewportContainer to update its viewport. @@ -116,7 +117,7 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, const LayoutPoint&) if (!firstChild() && !selfWillPaint()) return; - FloatRect repaintRect = repaintRectInLocalCoordinates(); + FloatRect repaintRect = paintInvalidationRectInLocalCoordinates(); if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(repaintRect, localToParentTransform(), paintInfo)) return; @@ -130,10 +131,14 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, const LayoutPoint&) childPaintInfo.applyTransform(localToParentTransform()); SVGRenderingContext renderingContext; + GraphicsContextCullSaver cullSaver(*childPaintInfo.context); bool continueRendering = true; if (childPaintInfo.phase == PaintPhaseForeground) { renderingContext.prepareToRenderSVGContent(this, childPaintInfo); continueRendering = renderingContext.isRenderingPrepared(); + + if (continueRendering && document().settings()->containerCullingEnabled()) + cullSaver.cull(paintInvalidationRectInLocalCoordinates()); } if (continueRendering) { @@ -144,11 +149,11 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, const LayoutPoint&) } // FIXME: This really should be drawn from local coordinates, but currently we hack it - // to avoid our clip killing our outline rect. Thus we translate our + // to avoid our clip killing our outline rect. Thus we translate our // outline rect into parent coords before drawing. // FIXME: This means our focus ring won't share our rotation like it should. // We should instead disable our clip during PaintPhaseOutline - if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE) { + if (paintInfo.phase == PaintPhaseForeground && style()->outlineWidth() && style()->visibility() == VISIBLE) { IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRect)); paintOutline(paintInfo, paintRectInParent); } @@ -157,7 +162,7 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, const LayoutPoint&) // addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call void RenderSVGContainer::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) { - IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates())); + IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(paintInvalidationRectInLocalCoordinates())); if (!paintRectInParent.isEmpty()) rects.append(paintRectInParent); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGContainer.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGContainer.h index fd4e74db96b..b7235fbaded 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGContainer.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGContainer.h @@ -37,12 +37,15 @@ public: RenderObject* firstChild() const { ASSERT(children() == virtualChildren()); return children()->firstChild(); } RenderObject* lastChild() const { ASSERT(children() == virtualChildren()); return children()->lastChild(); } + // If you have a RenderSVGContainer, use firstChild or lastChild instead. + void slowFirstChild() const WTF_DELETED_FUNCTION; + void slowLastChild() const WTF_DELETED_FUNCTION; + const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } - virtual void paint(PaintInfo&, const LayoutPoint&); + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; virtual void setNeedsBoundariesUpdate() OVERRIDE FINAL { m_needsBoundariesUpdate = true; } - virtual bool needsBoundariesUpdate() OVERRIDE FINAL { return m_needsBoundariesUpdate; } virtual bool didTransformToRootUpdate() { return false; } bool isObjectBoundingBoxValid() const { return m_objectBoundingBoxValid; } @@ -51,9 +54,9 @@ protected: virtual const RenderObjectChildList* virtualChildren() const OVERRIDE FINAL { return children(); } virtual bool isSVGContainer() const OVERRIDE FINAL { return true; } - virtual const char* renderName() const { return "RenderSVGContainer"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGContainer"; } - virtual void layout(); + virtual void layout() OVERRIDE; virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE FINAL; virtual void removeChild(RenderObject*) OVERRIDE FINAL; @@ -61,9 +64,9 @@ protected: virtual FloatRect objectBoundingBox() const OVERRIDE FINAL { return m_objectBoundingBox; } virtual FloatRect strokeBoundingBox() const OVERRIDE FINAL { return m_strokeBoundingBox; } - virtual FloatRect repaintRectInLocalCoordinates() const OVERRIDE FINAL { return m_repaintBoundingBox; } + virtual FloatRect paintInvalidationRectInLocalCoordinates() const OVERRIDE FINAL { return m_repaintBoundingBox; } - virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); + virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) OVERRIDE; // Allow RenderSVGTransformableContainer to hook in at the right time in layout() virtual bool calculateLocalTransform() { return false; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGEllipse.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGEllipse.cpp index ac5c6491fc3..b9a75029ae0 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGEllipse.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGEllipse.cpp @@ -28,9 +28,9 @@ #include "core/rendering/svg/RenderSVGEllipse.h" -#include "SVGNames.h" #include "core/svg/SVGCircleElement.h" #include "core/svg/SVGEllipseElement.h" +#include "platform/graphics/GraphicsContext.h" namespace WebCore { @@ -53,20 +53,22 @@ void RenderSVGEllipse::updateShapeFromElement() m_center = FloatPoint(); m_radii = FloatSize(); - // Fallback to RenderSVGShape if shape has a non-scaling stroke. - if (hasNonScalingStroke()) { - RenderSVGShape::updateShapeFromElement(); - m_usePathFallback = true; - return; - } else - m_usePathFallback = false; - calculateRadiiAndCenter(); - // Spec: "A value of zero disables rendering of the element." - if (m_radii.width() <= 0 || m_radii.height() <= 0) + // Spec: "A negative value is an error. A value of zero disables rendering of the element." + if (m_radii.width() < 0 || m_radii.height() < 0) return; + if (!m_radii.isEmpty()) { + // Fallback to RenderSVGShape if shape has a non-scaling stroke. + if (hasNonScalingStroke()) { + RenderSVGShape::updateShapeFromElement(); + m_usePathFallback = true; + return; + } + m_usePathFallback = false; + } + m_fillBoundingBox = FloatRect(m_center.x() - m_radii.width(), m_center.y() - m_radii.height(), 2 * m_radii.width(), 2 * m_radii.height()); m_strokeBoundingBox = m_fillBoundingBox; if (style()->svgStyle()->hasStroke()) @@ -76,21 +78,21 @@ void RenderSVGEllipse::updateShapeFromElement() void RenderSVGEllipse::calculateRadiiAndCenter() { ASSERT(element()); - if (element()->hasTagName(SVGNames::circleTag)) { - SVGCircleElement* circle = toSVGCircleElement(element()); + if (isSVGCircleElement(*element())) { + SVGCircleElement& circle = toSVGCircleElement(*element()); - SVGLengthContext lengthContext(circle); - float radius = circle->rCurrentValue().value(lengthContext); + SVGLengthContext lengthContext(&circle); + float radius = circle.r()->currentValue()->value(lengthContext); m_radii = FloatSize(radius, radius); - m_center = FloatPoint(circle->cxCurrentValue().value(lengthContext), circle->cyCurrentValue().value(lengthContext)); + m_center = FloatPoint(circle.cx()->currentValue()->value(lengthContext), circle.cy()->currentValue()->value(lengthContext)); return; } - SVGEllipseElement* ellipse = toSVGEllipseElement(element()); + SVGEllipseElement& ellipse = toSVGEllipseElement(*element()); - SVGLengthContext lengthContext(ellipse); - m_radii = FloatSize(ellipse->rxCurrentValue().value(lengthContext), ellipse->ryCurrentValue().value(lengthContext)); - m_center = FloatPoint(ellipse->cxCurrentValue().value(lengthContext), ellipse->cyCurrentValue().value(lengthContext)); + SVGLengthContext lengthContext(&ellipse); + m_radii = FloatSize(ellipse.rx()->currentValue()->value(lengthContext), ellipse.ry()->currentValue()->value(lengthContext)); + m_center = FloatPoint(ellipse.cx()->currentValue()->value(lengthContext), ellipse.cy()->currentValue()->value(lengthContext)); } void RenderSVGEllipse::fillShape(GraphicsContext* context) const diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGEllipse.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGEllipse.h index f06e5c16cf0..b73b5526853 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGEllipse.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGEllipse.h @@ -37,14 +37,14 @@ public: virtual ~RenderSVGEllipse(); private: - virtual const char* renderName() const { return "RenderSVGEllipse"; } - - virtual void updateShapeFromElement(); - virtual bool isEmpty() const { return m_usePathFallback ? RenderSVGShape::isEmpty() : m_fillBoundingBox.isEmpty(); }; - virtual void fillShape(GraphicsContext*) const; - virtual void strokeShape(GraphicsContext*) const; - virtual bool shapeDependentStrokeContains(const FloatPoint&); - virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const; + virtual const char* renderName() const OVERRIDE { return "RenderSVGEllipse"; } + + virtual void updateShapeFromElement() OVERRIDE; + virtual bool isShapeEmpty() const OVERRIDE { return m_usePathFallback ? RenderSVGShape::isShapeEmpty() : m_fillBoundingBox.isEmpty(); } + virtual void fillShape(GraphicsContext*) const OVERRIDE; + virtual void strokeShape(GraphicsContext*) const OVERRIDE; + virtual bool shapeDependentStrokeContains(const FloatPoint&) OVERRIDE; + virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const OVERRIDE; void calculateRadiiAndCenter(); private: diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGForeignObject.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGForeignObject.cpp index e27e037926f..9a9459836e1 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGForeignObject.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGForeignObject.cpp @@ -24,7 +24,6 @@ #include "core/rendering/svg/RenderSVGForeignObject.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/LayoutRepainter.h" #include "core/rendering/RenderView.h" #include "core/rendering/svg/SVGRenderSupport.h" @@ -45,6 +44,12 @@ RenderSVGForeignObject::~RenderSVGForeignObject() { } +bool RenderSVGForeignObject::isChildAllowed(RenderObject* child, RenderStyle* style) const +{ + // Disallow arbitary SVG content. Only allow proper <svg xmlns="svgNS"> subdocuments. + return !child->isSVG() || child->isSVGRoot(); +} + void RenderSVGForeignObject::paint(PaintInfo& paintInfo, const LayoutPoint&) { if (paintInfo.context->paintingDisabled() @@ -85,16 +90,6 @@ void RenderSVGForeignObject::paint(PaintInfo& paintInfo, const LayoutPoint&) } } -LayoutRect RenderSVGForeignObject::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const -{ - return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer); -} - -void RenderSVGForeignObject::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const -{ - SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaintRect, fixed); -} - const AffineTransform& RenderSVGForeignObject::localToParentTransform() const { m_localToParentTransform = localTransform(); @@ -121,9 +116,8 @@ void RenderSVGForeignObject::computeLogicalHeight(LayoutUnit, LayoutUnit logical void RenderSVGForeignObject::layout() { ASSERT(needsLayout()); - ASSERT(!view()->layoutStateEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree. + ASSERT(!view()->layoutStateCachedOffsetsEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree. - LayoutRectRecorder recorder(*this); LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(this)); SVGForeignObjectElement* foreign = toSVGForeignObjectElement(node()); @@ -138,8 +132,8 @@ void RenderSVGForeignObject::layout() // Cache viewport boundaries SVGLengthContext lengthContext(foreign); - FloatPoint viewportLocation(foreign->xCurrentValue().value(lengthContext), foreign->yCurrentValue().value(lengthContext)); - m_viewport = FloatRect(viewportLocation, FloatSize(foreign->widthCurrentValue().value(lengthContext), foreign->heightCurrentValue().value(lengthContext))); + FloatPoint viewportLocation(foreign->x()->currentValue()->value(lengthContext), foreign->y()->currentValue()->value(lengthContext)); + m_viewport = FloatRect(viewportLocation, FloatSize(foreign->width()->currentValue()->value(lengthContext), foreign->height()->currentValue()->value(lengthContext))); if (!updateCachedBoundariesInParents) updateCachedBoundariesInParents = oldViewport != m_viewport; @@ -165,6 +159,14 @@ void RenderSVGForeignObject::layout() repainter.repaintAfterLayout(); } +void RenderSVGForeignObject::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, + LayoutRect& rect, bool fixed) const +{ + FloatRect r(rect); + SVGRenderSupport::computeFloatRectForRepaint(this, paintInvalidationContainer, r, fixed); + rect = enclosingLayoutRect(r); +} + bool RenderSVGForeignObject::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) { // Embedded content is drawn in the foreground phase. @@ -184,20 +186,4 @@ bool RenderSVGForeignObject::nodeAtFloatPoint(const HitTestRequest& request, Hit || RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), HitTestChildBlockBackgrounds); } -bool RenderSVGForeignObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint&, HitTestAction) -{ - ASSERT_NOT_REACHED(); - return false; -} - -void RenderSVGForeignObject::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const -{ - SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed); -} - -const RenderObject* RenderSVGForeignObject::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const -{ - return SVGRenderSupport::pushMappingToContainer(this, ancestorToStopAt, geometryMap); -} - } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGForeignObject.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGForeignObject.h index 63cdac1d35b..d57b723aa18 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGForeignObject.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGForeignObject.h @@ -32,38 +32,32 @@ public: explicit RenderSVGForeignObject(SVGForeignObjectElement*); virtual ~RenderSVGForeignObject(); - virtual const char* renderName() const { return "RenderSVGForeignObject"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGForeignObject"; } - virtual void paint(PaintInfo&, const LayoutPoint&); + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE; - virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed = false) const OVERRIDE; + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; - virtual bool requiresLayer() const { return false; } - virtual void layout(); + virtual void layout() OVERRIDE; - virtual FloatRect objectBoundingBox() const { return FloatRect(FloatPoint(), m_viewport.size()); } - virtual FloatRect strokeBoundingBox() const { return FloatRect(FloatPoint(), m_viewport.size()); } - virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(FloatPoint(), m_viewport.size()); } + virtual FloatRect objectBoundingBox() const OVERRIDE { return FloatRect(FloatPoint(), m_viewport.size()); } + virtual FloatRect strokeBoundingBox() const OVERRIDE { return FloatRect(FloatPoint(), m_viewport.size()); } + virtual FloatRect paintInvalidationRectInLocalCoordinates() const OVERRIDE { return FloatRect(FloatPoint(), m_viewport.size()); } - virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; - virtual bool isSVGForeignObject() const { return true; } + virtual void mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect&, bool fixed = false) const OVERRIDE; + virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) OVERRIDE; + virtual bool isSVGForeignObject() const OVERRIDE { return true; } - virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE; - virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE; - virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } + virtual void setNeedsTransformUpdate() OVERRIDE { m_needsTransformUpdate = true; } private: virtual void updateLogicalWidth() OVERRIDE; virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE; - virtual const AffineTransform& localToParentTransform() const; - virtual AffineTransform localTransform() const { return m_localTransform; } + virtual const AffineTransform& localToParentTransform() const OVERRIDE; bool m_needsTransformUpdate : 1; FloatRect m_viewport; - AffineTransform m_localTransform; mutable AffineTransform m_localToParentTransform; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGGradientStop.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGGradientStop.cpp index ca5f315a7bc..d9ce3bf7015 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGGradientStop.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGGradientStop.cpp @@ -21,15 +21,12 @@ #include "core/rendering/svg/RenderSVGGradientStop.h" -#include "SVGNames.h" #include "core/rendering/svg/RenderSVGResourceContainer.h" #include "core/svg/SVGGradientElement.h" #include "core/svg/SVGStopElement.h" namespace WebCore { -using namespace SVGNames; - RenderSVGGradientStop::RenderSVGGradientStop(SVGStopElement* element) : RenderObject(element) { @@ -42,7 +39,7 @@ RenderSVGGradientStop::~RenderSVGGradientStop() void RenderSVGGradientStop::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderObject::styleDidChange(diff, oldStyle); - if (diff == StyleDifferenceEqual) + if (diff.hasNoChange()) return; // <stop> elements should only be allowed to make renderers under gradient elements @@ -67,9 +64,8 @@ void RenderSVGGradientStop::layout() SVGGradientElement* RenderSVGGradientStop::gradientElement() const { ContainerNode* parentNode = node()->parentNode(); - if (parentNode->hasTagName(linearGradientTag) || parentNode->hasTagName(radialGradientTag)) - return toSVGGradientElement(parentNode); - return 0; + ASSERT(parentNode); + return isSVGGradientElement(*parentNode) ? toSVGGradientElement(parentNode) : 0; } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGGradientStop.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGGradientStop.h index e56274e3ffc..4d6fee11121 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGGradientStop.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGGradientStop.h @@ -34,21 +34,22 @@ public: explicit RenderSVGGradientStop(SVGStopElement*); virtual ~RenderSVGGradientStop(); - virtual bool isSVGGradientStop() const { return true; } - virtual const char* renderName() const { return "RenderSVGGradientStop"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGGradientStop"; } + virtual bool isSVGGradientStop() const OVERRIDE { return true; } + virtual bool isSVG() const OVERRIDE { return true; } - virtual void layout(); + virtual void layout() OVERRIDE; // This overrides are needed to prevent ASSERTs on <svg><stop /></svg> // RenderObject's default implementations ASSERT_NOT_REACHED() // https://bugs.webkit.org/show_bug.cgi?id=20400 - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject*) const OVERRIDE { return LayoutRect(); } - virtual FloatRect objectBoundingBox() const { return FloatRect(); } - virtual FloatRect strokeBoundingBox() const { return FloatRect(); } - virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); } + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject*) const OVERRIDE { return LayoutRect(); } + virtual FloatRect objectBoundingBox() const OVERRIDE { return FloatRect(); } + virtual FloatRect strokeBoundingBox() const OVERRIDE { return FloatRect(); } + virtual FloatRect paintInvalidationRectInLocalCoordinates() const OVERRIDE { return FloatRect(); } protected: - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; private: SVGGradientElement* gradientElement() const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGHiddenContainer.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGHiddenContainer.cpp index 0f1578935a5..0e5af52bb57 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGHiddenContainer.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGHiddenContainer.cpp @@ -20,8 +20,7 @@ #include "config.h" #include "core/rendering/svg/RenderSVGHiddenContainer.h" - -#include "core/rendering/LayoutRectRecorder.h" +#include "core/rendering/svg/SVGRenderSupport.h" namespace WebCore { @@ -33,7 +32,6 @@ RenderSVGHiddenContainer::RenderSVGHiddenContainer(SVGElement* element) void RenderSVGHiddenContainer::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); SVGRenderSupport::layoutChildren(this, selfNeedsLayout()); updateCachedBoundaries(); clearNeedsLayout(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGHiddenContainer.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGHiddenContainer.h index f8e57d33f1d..0616b76b719 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGHiddenContainer.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGHiddenContainer.h @@ -32,17 +32,17 @@ class RenderSVGHiddenContainer : public RenderSVGContainer { public: explicit RenderSVGHiddenContainer(SVGElement*); - virtual const char* renderName() const { return "RenderSVGHiddenContainer"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGHiddenContainer"; } protected: - virtual void layout(); + virtual void layout() OVERRIDE; private: virtual bool isSVGHiddenContainer() const OVERRIDE FINAL { return true; } virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE FINAL; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject*) const OVERRIDE FINAL { return LayoutRect(); } + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject*) const OVERRIDE FINAL { return LayoutRect(); } virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const OVERRIDE FINAL; virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) OVERRIDE FINAL; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGImage.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGImage.cpp index 9e2e4cd9414..b483670d4f2 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGImage.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGImage.cpp @@ -29,11 +29,11 @@ #include "core/rendering/GraphicsContextAnnotator.h" #include "core/rendering/ImageQualityController.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/LayoutRepainter.h" #include "core/rendering/PointerEventsHitRules.h" #include "core/rendering/RenderImageResource.h" #include "core/rendering/svg/RenderSVGResource.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGRenderingContext.h" #include "core/rendering/svg/SVGResources.h" #include "core/rendering/svg/SVGResourcesCache.h" @@ -64,12 +64,12 @@ bool RenderSVGImage::updateImageViewport() bool updatedViewport = false; SVGLengthContext lengthContext(image); - m_objectBoundingBox = FloatRect(image->xCurrentValue().value(lengthContext), image->yCurrentValue().value(lengthContext), image->widthCurrentValue().value(lengthContext), image->heightCurrentValue().value(lengthContext)); + m_objectBoundingBox = FloatRect(image->x()->currentValue()->value(lengthContext), image->y()->currentValue()->value(lengthContext), image->width()->currentValue()->value(lengthContext), image->height()->currentValue()->value(lengthContext)); // Images with preserveAspectRatio=none should force non-uniform scaling. This can be achieved // by setting the image's container size to its intrinsic size. // See: http://www.w3.org/TR/SVG/single-page.html, 7.8 The ‘preserveAspectRatio’ attribute. - if (image->preserveAspectRatioCurrentValue().align() == SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) { + if (image->preserveAspectRatio()->currentValue()->align() == SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) { if (ImageResource* cachedImage = m_imageResource->cachedImage()) { LayoutSize intrinsicSize = cachedImage->imageSizeForRenderer(0, style()->effectiveZoom()); if (intrinsicSize != m_imageResource->imageSize(style()->effectiveZoom())) { @@ -93,7 +93,6 @@ void RenderSVGImage::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(this) && selfNeedsLayout()); updateImageViewport(); @@ -126,33 +125,38 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, const LayoutPoint&) { ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this); - if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || !m_imageResource->hasImage()) + if (paintInfo.context->paintingDisabled() + || paintInfo.phase != PaintPhaseForeground + || style()->visibility() == HIDDEN + || !m_imageResource->hasImage()) return; - FloatRect boundingBox = repaintRectInLocalCoordinates(); + FloatRect boundingBox = paintInvalidationRectInLocalCoordinates(); if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(boundingBox, m_localTransform, paintInfo)) return; PaintInfo childPaintInfo(paintInfo); - bool drawsOutline = style()->outlineWidth() && (childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline); - if (drawsOutline || childPaintInfo.phase == PaintPhaseForeground) { - GraphicsContextStateSaver stateSaver(*childPaintInfo.context); - childPaintInfo.applyTransform(m_localTransform); + GraphicsContextStateSaver stateSaver(*childPaintInfo.context, false); - if (childPaintInfo.phase == PaintPhaseForeground && !m_objectBoundingBox.isEmpty()) { - SVGRenderingContext renderingContext(this, childPaintInfo); + if (!m_localTransform.isIdentity()) { + stateSaver.save(); + childPaintInfo.applyTransform(m_localTransform, false); + } + if (!m_objectBoundingBox.isEmpty()) { + // SVGRenderingContext may taint the state - make sure we're always saving. + SVGRenderingContext renderingContext(this, childPaintInfo, stateSaver.saved() ? + SVGRenderingContext::DontSaveGraphicsContext : SVGRenderingContext::SaveGraphicsContext); - if (renderingContext.isRenderingPrepared()) { - if (style()->svgStyle()->bufferedRendering() == BR_STATIC && renderingContext.bufferForeground(m_bufferedForeground)) - return; + if (renderingContext.isRenderingPrepared()) { + if (style()->svgStyle()->bufferedRendering() == BR_STATIC && renderingContext.bufferForeground(m_bufferedForeground)) + return; - paintForeground(childPaintInfo); - } + paintForeground(childPaintInfo); } - - if (drawsOutline) - paintOutline(childPaintInfo, IntRect(boundingBox)); } + + if (style()->outlineWidth()) + paintOutline(childPaintInfo, IntRect(boundingBox)); } void RenderSVGImage::paintForeground(PaintInfo& paintInfo) @@ -162,13 +166,16 @@ void RenderSVGImage::paintForeground(PaintInfo& paintInfo) FloatRect srcRect(0, 0, image->width(), image->height()); SVGImageElement* imageElement = toSVGImageElement(element()); - imageElement->preserveAspectRatioCurrentValue().transformRect(destRect, srcRect); + imageElement->preserveAspectRatio()->currentValue()->transformRect(destRect, srcRect); - bool useLowQualityScaling = false; + InterpolationQuality interpolationQuality = InterpolationDefault; if (style()->svgStyle()->bufferedRendering() != BR_STATIC) - useLowQualityScaling = ImageQualityController::imageQualityController()->shouldPaintAtLowQuality(paintInfo.context, this, image.get(), image.get(), LayoutSize(destRect.size())); + interpolationQuality = ImageQualityController::imageQualityController()->chooseInterpolationQuality(paintInfo.context, this, image.get(), image.get(), LayoutSize(destRect.size())); - paintInfo.context->drawImage(image.get(), destRect, srcRect, CompositeSourceOver, DoNotRespectImageOrientation, useLowQualityScaling); + InterpolationQuality previousInterpolationQuality = paintInfo.context->imageInterpolationQuality(); + paintInfo.context->setImageInterpolationQuality(interpolationQuality); + paintInfo.context->drawImage(image.get(), destRect, srcRect, CompositeSourceOver); + paintInfo.context->setImageInterpolationQuality(previousInterpolationQuality); } void RenderSVGImage::invalidateBufferedForeground() @@ -218,13 +225,13 @@ void RenderSVGImage::imageChanged(WrappedImagePtr, const IntRect*) invalidateBufferedForeground(); - repaint(); + paintInvalidationForWholeRenderer(); } void RenderSVGImage::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) { // this is called from paint() after the localTransform has already been applied - IntRect contentRect = enclosingIntRect(repaintRectInLocalCoordinates()); + IntRect contentRect = enclosingIntRect(paintInvalidationRectInLocalCoordinates()); if (!contentRect.isEmpty()) rects.append(contentRect); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGImage.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGImage.h index e87392e04fa..644bdd15027 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGImage.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGImage.h @@ -37,9 +37,8 @@ public: virtual ~RenderSVGImage(); bool updateImageViewport(); - virtual void setNeedsBoundariesUpdate() { m_needsBoundariesUpdate = true; } - virtual bool needsBoundariesUpdate() OVERRIDE { return m_needsBoundariesUpdate; } - virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } + virtual void setNeedsBoundariesUpdate() OVERRIDE { m_needsBoundariesUpdate = true; } + virtual void setNeedsTransformUpdate() OVERRIDE { m_needsTransformUpdate = true; } RenderImageResource* imageResource() { return m_imageResource.get(); } @@ -47,27 +46,27 @@ public: void paintForeground(PaintInfo&); private: - virtual const char* renderName() const { return "RenderSVGImage"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGImage"; } virtual bool isSVGImage() const OVERRIDE { return true; } - virtual const AffineTransform& localToParentTransform() const { return m_localTransform; } + virtual const AffineTransform& localToParentTransform() const OVERRIDE { return m_localTransform; } - virtual FloatRect objectBoundingBox() const { return m_objectBoundingBox; } - virtual FloatRect strokeBoundingBox() const { return m_objectBoundingBox; } - virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; } + virtual FloatRect objectBoundingBox() const OVERRIDE { return m_objectBoundingBox; } + virtual FloatRect strokeBoundingBox() const OVERRIDE { return m_objectBoundingBox; } + virtual FloatRect paintInvalidationRectInLocalCoordinates() const OVERRIDE { return m_repaintBoundingBox; } virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) OVERRIDE; - virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) OVERRIDE; - virtual void layout(); - virtual void paint(PaintInfo&, const LayoutPoint&); + virtual void layout() OVERRIDE; + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; void invalidateBufferedForeground(); - virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); + virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) OVERRIDE; - virtual AffineTransform localTransform() const { return m_localTransform; } + virtual AffineTransform localTransform() const OVERRIDE { return m_localTransform; } bool m_needsBoundariesUpdate : 1; bool m_needsTransformUpdate : 1; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInline.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInline.cpp index 68b1a4029cd..07c0a58c4d9 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInline.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInline.cpp @@ -27,12 +27,22 @@ #include "core/rendering/svg/SVGInlineFlowBox.h" #include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGResourcesCache.h" +#include "core/svg/SVGAElement.h" namespace WebCore { bool RenderSVGInline::isChildAllowed(RenderObject* child, RenderStyle* style) const { - if (SVGRenderSupport::isEmptySVGInlineText(child)) + if (child->isText()) + return SVGRenderSupport::isRenderableTextNode(child); + + if (isSVGAElement(*node())) { + // Disallow direct descendant 'a'. + if (isSVGAElement(*child->node())) + return false; + } + + if (!child->isSVGInline() && !child->isSVGInlineText()) return false; return RenderInline::isChildAllowed(child, style); @@ -46,7 +56,7 @@ RenderSVGInline::RenderSVGInline(Element* element) InlineFlowBox* RenderSVGInline::createInlineFlowBox() { - InlineFlowBox* box = new SVGInlineFlowBox(this); + InlineFlowBox* box = new SVGInlineFlowBox(*this); box->setHasVirtualLogicalHeight(); return box; } @@ -67,22 +77,22 @@ FloatRect RenderSVGInline::strokeBoundingBox() const return FloatRect(); } -FloatRect RenderSVGInline::repaintRectInLocalCoordinates() const +FloatRect RenderSVGInline::paintInvalidationRectInLocalCoordinates() const { if (const RenderObject* object = RenderSVGText::locateRenderSVGTextAncestor(this)) - return object->repaintRectInLocalCoordinates(); + return object->paintInvalidationRectInLocalCoordinates(); return FloatRect(); } -LayoutRect RenderSVGInline::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const +LayoutRect RenderSVGInline::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const { - return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer); + return SVGRenderSupport::clippedOverflowRectForRepaint(this, paintInvalidationContainer); } -void RenderSVGInline::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const +void RenderSVGInline::computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect& paintInvalidationRect, bool fixed) const { - SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaintRect, fixed); + SVGRenderSupport::computeFloatRectForRepaint(this, paintInvalidationContainer, paintInvalidationRect, fixed); } void RenderSVGInline::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const @@ -114,7 +124,7 @@ void RenderSVGInline::willBeDestroyed() void RenderSVGInline::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - if (diff == StyleDifferenceLayout) + if (diff.needsFullLayout()) setNeedsBoundariesUpdate(); RenderInline::styleDidChange(diff, oldStyle); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInline.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInline.h index 43634a39c22..1c09c5666f6 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInline.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInline.h @@ -29,9 +29,10 @@ class RenderSVGInline : public RenderInline { public: explicit RenderSVGInline(Element*); - virtual const char* renderName() const { return "RenderSVGInline"; } - virtual bool requiresLayer() const OVERRIDE FINAL { return false; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGInline"; } + virtual LayerType layerTypeRequired() const OVERRIDE FINAL { return NoLayer; } virtual bool isSVGInline() const OVERRIDE FINAL { return true; } + virtual bool isSVG() const OVERRIDE FINAL { return true; } virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; @@ -42,10 +43,10 @@ public: // this element, since we need it for filters. virtual FloatRect objectBoundingBox() const OVERRIDE FINAL; virtual FloatRect strokeBoundingBox() const OVERRIDE FINAL; - virtual FloatRect repaintRectInLocalCoordinates() const OVERRIDE FINAL; + virtual FloatRect paintInvalidationRectInLocalCoordinates() const OVERRIDE FINAL; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE FINAL; - virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed = false) const OVERRIDE FINAL; + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const OVERRIDE FINAL; + virtual void computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect&, bool fixed = false) const OVERRIDE FINAL; virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE FINAL; virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE FINAL; virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const OVERRIDE FINAL; @@ -60,6 +61,8 @@ private: virtual void removeChild(RenderObject*) OVERRIDE FINAL; }; +DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderSVGInline, isSVGInline()); + } #endif // !RenderSVGTSpan_H diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInlineText.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInlineText.cpp index e8041f8c1c2..d19fed0516d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInlineText.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInlineText.cpp @@ -89,17 +89,17 @@ void RenderSVGInlineText::styleDidChange(StyleDifference diff, const RenderStyle return; } - if (diff != StyleDifferenceLayout) + if (!diff.needsFullLayout()) return; // The text metrics may be influenced by style changes. if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this)) - textRenderer->subtreeStyleDidChange(this); + textRenderer->setNeedsLayoutAndFullPaintInvalidation(); } InlineTextBox* RenderSVGInlineText::createTextBox() { - InlineTextBox* box = new SVGInlineTextBox(this); + InlineTextBox* box = new SVGInlineTextBox(*this); box->setHasVirtualLogicalHeight(); return box; } @@ -186,8 +186,7 @@ PositionWithAffinity RenderSVGInlineText::positionForPoint(const LayoutPoint& po const SVGTextFragment& fragment = fragments.at(i); FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); fragment.buildFragmentTransform(fragmentTransform); - if (!fragmentTransform.isIdentity()) - fragmentRect = fragmentTransform.mapRect(fragmentRect); + fragmentRect = fragmentTransform.mapRect(fragmentRect); float distance = powf(fragmentRect.x() - absolutePoint.x(), 2) + powf(fragmentRect.y() + fragmentRect.height() / 2 - absolutePoint.y(), 2); @@ -226,7 +225,7 @@ void RenderSVGInlineText::computeNewScaledFontForStyle(RenderObject* renderer, c return; } - if (style->fontDescription().textRenderingMode() == GeometricPrecision) + if (style->fontDescription().textRendering() == GeometricPrecision) scalingFactor = 1; FontDescription fontDescription(style->fontDescription()); @@ -235,7 +234,7 @@ void RenderSVGInlineText::computeNewScaledFontForStyle(RenderObject* renderer, c // FIXME: We need to better handle the case when we compute very small fonts below (below 1pt). fontDescription.setComputedSize(FontSize::getComputedSizeFromSpecifiedSize(&document, scalingFactor, fontDescription.isAbsoluteSize(), fontDescription.specifiedSize(), DoNotUseSmartMinimumForFontSize)); - scaledFont = Font(fontDescription, 0, 0); + scaledFont = Font(fontDescription); scaledFont.update(document.styleEngine()->fontSelector()); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInlineText.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInlineText.h index 8c7f711a68f..b7fc9add99b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInlineText.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInlineText.h @@ -27,8 +27,6 @@ namespace WebCore { -class SVGInlineTextBox; - class RenderSVGInlineText FINAL : public RenderText { public: RenderSVGInlineText(Node*, PassRefPtr<StringImpl>); @@ -45,19 +43,20 @@ public: FloatRect floatLinesBoundingBox() const; private: - virtual const char* renderName() const { return "RenderSVGInlineText"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGInlineText"; } - virtual void setTextInternal(PassRefPtr<StringImpl>); - virtual void styleDidChange(StyleDifference, const RenderStyle*); + virtual void setTextInternal(PassRefPtr<StringImpl>) OVERRIDE; + virtual void styleDidChange(StyleDifference, const RenderStyle*) OVERRIDE; - virtual FloatRect objectBoundingBox() const { return floatLinesBoundingBox(); } + virtual FloatRect objectBoundingBox() const OVERRIDE { return floatLinesBoundingBox(); } - virtual bool isSVGInlineText() const { return true; } + virtual bool isSVGInlineText() const OVERRIDE { return true; } + virtual bool isSVG() const OVERRIDE { return true; } - virtual PositionWithAffinity positionForPoint(const LayoutPoint&) OVERRIDE FINAL; - virtual LayoutRect localCaretRect(InlineBox*, int caretOffset, LayoutUnit* extraWidthToEndOfLine = 0); - virtual IntRect linesBoundingBox() const; - virtual InlineTextBox* createTextBox(); + virtual PositionWithAffinity positionForPoint(const LayoutPoint&) OVERRIDE; + virtual LayoutRect localCaretRect(InlineBox*, int caretOffset, LayoutUnit* extraWidthToEndOfLine = 0) OVERRIDE; + virtual IntRect linesBoundingBox() const OVERRIDE; + virtual InlineTextBox* createTextBox() OVERRIDE; float m_scalingFactor; Font m_scaledFont; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGModelObject.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGModelObject.cpp index 12da706b521..a6918a93535 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGModelObject.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGModelObject.cpp @@ -29,11 +29,12 @@ */ #include "config.h" - #include "core/rendering/svg/RenderSVGModelObject.h" -#include "SVGNames.h" +#include "core/rendering/RenderLayer.h" +#include "core/rendering/RenderView.h" #include "core/rendering/svg/RenderSVGRoot.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGResourcesCache.h" #include "core/svg/SVGGraphicsElement.h" @@ -44,14 +45,19 @@ RenderSVGModelObject::RenderSVGModelObject(SVGElement* node) { } -LayoutRect RenderSVGModelObject::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const +bool RenderSVGModelObject::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + return child->isSVG() && !(child->isSVGInline() || child->isSVGInlineText()); +} + +LayoutRect RenderSVGModelObject::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const { - return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer); + return SVGRenderSupport::clippedOverflowRectForRepaint(this, paintInvalidationContainer); } -void RenderSVGModelObject::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const +void RenderSVGModelObject::computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect& paintInvalidationRect, bool fixed) const { - SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaintRect, fixed); + SVGRenderSupport::computeFloatRectForRepaint(this, paintInvalidationContainer, paintInvalidationRect, fixed); } void RenderSVGModelObject::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const @@ -64,18 +70,6 @@ const RenderObject* RenderSVGModelObject::pushMappingToContainer(const RenderLay return SVGRenderSupport::pushMappingToContainer(this, ancestorToStopAt, geometryMap); } -// Copied from RenderBox, this method likely requires further refactoring to work easily for both SVG and CSS Box Model content. -// FIXME: This may also need to move into SVGRenderSupport as the RenderBox version depends -// on borderBoundingBox() which SVG RenderBox subclases (like SVGRenderBlock) do not implement. -LayoutRect RenderSVGModelObject::outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap*) const -{ - LayoutRect box = enclosingLayoutRect(repaintRectInLocalCoordinates()); - adjustRectForOutlineAndShadow(box); - - FloatQuad containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer); - return containerRelativeQuad.enclosingBoundingBox(); -} - void RenderSVGModelObject::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const { IntRect rect = enclosingIntRect(strokeBoundingBox()); @@ -107,7 +101,7 @@ void RenderSVGModelObject::addLayerHitTestRects(LayerHitTestRects&, const Render void RenderSVGModelObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - if (diff == StyleDifferenceLayout) { + if (diff.needsFullLayout()) { setNeedsBoundariesUpdate(); if (style()->hasTransform()) setNeedsTransformUpdate(); @@ -123,82 +117,53 @@ bool RenderSVGModelObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, co return false; } -static void getElementCTM(SVGGraphicsElement* element, AffineTransform& transform) +// The SVG addFocusRingRects() method adds rects in local coordinates so the default absoluteFocusRingQuads +// returns incorrect values for SVG objects. Overriding this method provides access to the absolute bounds. +void RenderSVGModelObject::absoluteFocusRingQuads(Vector<FloatQuad>& quads) { - ASSERT(element); - element->document().updateLayoutIgnorePendingStylesheets(); - - SVGElement* stopAtElement = element->nearestViewportElement(); - ASSERT(stopAtElement); + quads.append(localToAbsoluteQuad(FloatQuad(paintInvalidationRectInLocalCoordinates()))); +} - AffineTransform localTransform; - Node* current = element; +void RenderSVGModelObject::invalidateTreeAfterLayout(const RenderLayerModelObject& paintInvalidationContainer) +{ + // Note: This is a reduced version of RenderBox::invalidateTreeAfterLayout(). + // FIXME: Should share code with RenderBox::invalidateTreeAfterLayout(). + ASSERT(RuntimeEnabledFeatures::repaintAfterLayoutEnabled()); + ASSERT(!needsLayout()); - while (current && current->isSVGElement()) { - SVGElement* currentElement = toSVGElement(current); - localTransform = currentElement->renderer()->localToParentTransform(); - transform = localTransform.multiply(transform); - // For getCTM() computation, stop at the nearest viewport element - if (currentElement == stopAtElement) - break; + if (!shouldCheckForPaintInvalidationAfterLayout()) + return; - current = current->parentOrShadowHostNode(); - } -} + ForceHorriblySlowRectMapping slowRectMapping(*this); -// FloatRect::intersects does not consider horizontal or vertical lines (because of isEmpty()). -// So special-case handling of such lines. -static bool intersectsAllowingEmpty(const FloatRect& r, const FloatRect& other) -{ - if (r.isEmpty() && other.isEmpty()) - return false; - if (r.isEmpty() && !other.isEmpty()) { - return (other.contains(r.x(), r.y()) && !other.contains(r.maxX(), r.maxY())) - || (!other.contains(r.x(), r.y()) && other.contains(r.maxX(), r.maxY())); - } - if (other.isEmpty() && !r.isEmpty()) - return intersectsAllowingEmpty(other, r); - return r.intersects(other); -} + const LayoutRect oldPaintInvalidationRect = previousPaintInvalidationRect(); + const LayoutPoint oldPositionFromPaintInvalidationContainer = previousPositionFromPaintInvalidationContainer(); + const RenderLayerModelObject& newPaintInvalidationContainer = *containerForPaintInvalidation(); + setPreviousPaintInvalidationRect(clippedOverflowRectForPaintInvalidation(&newPaintInvalidationContainer)); + setPreviousPositionFromPaintInvalidationContainer(RenderLayer::positionFromPaintInvalidationContainer(this, &newPaintInvalidationContainer)); -// One of the element types that can cause graphics to be drawn onto the target canvas. Specifically: circle, ellipse, -// image, line, path, polygon, polyline, rect, text and use. -static bool isGraphicsElement(RenderObject* renderer) -{ - return renderer->isSVGShape() || renderer->isSVGText() || renderer->isSVGImage() || renderer->node()->hasTagName(SVGNames::useTag); -} + // If an ancestor container had its transform changed, then we just + // need to update the RenderSVGModelObject's repaint rect above. The invalidation + // will be handled by the container where the transform changed. This essentially + // means that we prune the entire branch for performance. + if (!SVGRenderSupport::parentTransformDidChange(this)) + return; -// The SVG addFocusRingRects() method adds rects in local coordinates so the default absoluteFocusRingQuads -// returns incorrect values for SVG objects. Overriding this method provides access to the absolute bounds. -void RenderSVGModelObject::absoluteFocusRingQuads(Vector<FloatQuad>& quads) -{ - quads.append(localToAbsoluteQuad(FloatQuad(repaintRectInLocalCoordinates()))); -} + // If we are set to do a full paint invalidation that means the RenderView will be + // issue paint invalidations. We can then skip issuing of paint invalidations for the child + // renderers as they'll be covered by the RenderView. + if (view()->doingFullRepaint()) { + RenderObject::invalidateTreeAfterLayout(newPaintInvalidationContainer); + return; + } -bool RenderSVGModelObject::checkIntersection(RenderObject* renderer, const SVGRect& rect) -{ - if (!renderer || renderer->style()->pointerEvents() == PE_NONE) - return false; - if (!isGraphicsElement(renderer)) - return false; - AffineTransform ctm; - SVGGraphicsElement* svgElement = toSVGGraphicsElement(renderer->node()); - getElementCTM(svgElement, ctm); - ASSERT(svgElement->renderer()); - return intersectsAllowingEmpty(rect, ctm.mapRect(svgElement->renderer()->repaintRectInLocalCoordinates())); -} + const LayoutRect& newPaintInvalidationRect = previousPaintInvalidationRect(); + const LayoutPoint& newPositionFromPaintInvalidationContainer = previousPositionFromPaintInvalidationContainer(); + invalidatePaintAfterLayoutIfNeeded(containerForPaintInvalidation(), + shouldDoFullPaintInvalidationAfterLayout(), oldPaintInvalidationRect, oldPositionFromPaintInvalidationContainer, + &newPaintInvalidationRect, &newPositionFromPaintInvalidationContainer); -bool RenderSVGModelObject::checkEnclosure(RenderObject* renderer, const SVGRect& rect) -{ - if (!renderer || renderer->style()->pointerEvents() == PE_NONE) - return false; - if (!isGraphicsElement(renderer)) - return false; - AffineTransform ctm; - SVGGraphicsElement* svgElement = toSVGGraphicsElement(renderer->node()); - getElementCTM(svgElement, ctm); - ASSERT(svgElement->renderer()); - return rect.contains(ctm.mapRect(svgElement->renderer()->repaintRectInLocalCoordinates())); + RenderObject::invalidateTreeAfterLayout(newPaintInvalidationContainer); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGModelObject.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGModelObject.h index c8df10aca7d..41bc62ae412 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGModelObject.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGModelObject.h @@ -32,9 +32,8 @@ #define RenderSVGModelObject_h #include "core/rendering/RenderObject.h" -#include "core/rendering/svg/SVGRenderSupport.h" #include "core/svg/SVGElement.h" -#include "core/svg/SVGRect.h" +#include "platform/geometry/FloatRect.h" namespace WebCore { @@ -49,34 +48,37 @@ class RenderSVGModelObject : public RenderObject { public: explicit RenderSVGModelObject(SVGElement*); - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE; - virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed = false) const OVERRIDE FINAL; - virtual LayoutRect outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap*) const OVERRIDE FINAL; + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; + virtual bool canHaveWhitespaceChildren() const OVERRIDE { return false; } + + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const OVERRIDE; + virtual void computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect&, bool fixed = false) const OVERRIDE FINAL; virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const OVERRIDE FINAL; - virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; + virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const OVERRIDE; virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE FINAL; virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE FINAL; - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - - static bool checkIntersection(RenderObject*, const SVGRect&); - static bool checkEnclosure(RenderObject*, const SVGRect&); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; - virtual void computeLayerHitTestRects(LayerHitTestRects&) const OVERRIDE; + virtual void computeLayerHitTestRects(LayerHitTestRects&) const OVERRIDE FINAL; SVGElement* element() const { return toSVGElement(RenderObject::node()); } + virtual bool isSVG() const OVERRIDE FINAL { return true; } + + virtual void invalidateTreeAfterLayout(const RenderLayerModelObject&) OVERRIDE; + protected: - virtual void addLayerHitTestRects(LayerHitTestRects&, const RenderLayer* currentCompositedLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const OVERRIDE; - virtual void willBeDestroyed(); + virtual void addLayerHitTestRects(LayerHitTestRects&, const RenderLayer* currentCompositedLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const OVERRIDE FINAL; + virtual void willBeDestroyed() OVERRIDE; private: // RenderSVGModelObject subclasses should use element() instead. void node() const WTF_DELETED_FUNCTION; // This method should never be called, SVG uses a different nodeAtPoint method - bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE FINAL; virtual void absoluteFocusRingQuads(Vector<FloatQuad>&) OVERRIDE FINAL; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGPath.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGPath.h index 8cec15c4c92..48b36762e04 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGPath.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGPath.h @@ -37,7 +37,7 @@ public: private: virtual bool isSVGPath() const OVERRIDE { return true; } - virtual const char* renderName() const { return "RenderSVGPath"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGPath"; } virtual void updateShapeFromElement() OVERRIDE; FloatRect calculateUpdatedStrokeBoundingBox() const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRect.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRect.cpp index dfe447156f6..5fd79e7f626 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRect.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRect.cpp @@ -28,8 +28,7 @@ #include "config.h" #include "core/rendering/svg/RenderSVGRect.h" - -#include "SVGNames.h" +#include "platform/graphics/GraphicsContext.h" namespace WebCore { @@ -54,19 +53,24 @@ void RenderSVGRect::updateShapeFromElement() ASSERT(rect); SVGLengthContext lengthContext(rect); - // Fallback to RenderSVGShape if rect has rounded corners or a non-scaling stroke. - if (rect->rxCurrentValue().value(lengthContext) > 0 || rect->ryCurrentValue().value(lengthContext) > 0 || hasNonScalingStroke()) { - RenderSVGShape::updateShapeFromElement(); - m_usePathFallback = true; - return; - } + FloatSize boundingBoxSize(rect->width()->currentValue()->value(lengthContext), rect->height()->currentValue()->value(lengthContext)); - m_usePathFallback = false; - FloatSize boundingBoxSize(rect->widthCurrentValue().value(lengthContext), rect->heightCurrentValue().value(lengthContext)); - if (boundingBoxSize.isEmpty()) + // Spec: "A negative value is an error." + if (boundingBoxSize.width() < 0 || boundingBoxSize.height() < 0) return; - m_fillBoundingBox = FloatRect(FloatPoint(rect->xCurrentValue().value(lengthContext), rect->yCurrentValue().value(lengthContext)), boundingBoxSize); + // Spec: "A value of zero disables rendering of the element." + if (!boundingBoxSize.isEmpty()) { + // Fallback to RenderSVGShape if rect has rounded corners or a non-scaling stroke. + if (rect->rx()->currentValue()->value(lengthContext) > 0 || rect->ry()->currentValue()->value(lengthContext) > 0 || hasNonScalingStroke()) { + RenderSVGShape::updateShapeFromElement(); + m_usePathFallback = true; + return; + } + m_usePathFallback = false; + } + + m_fillBoundingBox = FloatRect(FloatPoint(rect->x()->currentValue()->value(lengthContext), rect->y()->currentValue()->value(lengthContext)), boundingBoxSize); // To decide if the stroke contains a point we create two rects which represent the inner and // the outer stroke borders. A stroke contains the point, if the point is between them. diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRect.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRect.h index 1a5d6e091e4..7ae39625755 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRect.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRect.h @@ -39,14 +39,14 @@ public: virtual ~RenderSVGRect(); private: - virtual const char* renderName() const { return "RenderSVGRect"; } - - virtual void updateShapeFromElement(); - virtual bool isEmpty() const { return m_usePathFallback ? RenderSVGShape::isEmpty() : m_fillBoundingBox.isEmpty(); }; - virtual void fillShape(GraphicsContext*) const; - virtual void strokeShape(GraphicsContext*) const; - virtual bool shapeDependentStrokeContains(const FloatPoint&); - virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const; + virtual const char* renderName() const OVERRIDE { return "RenderSVGRect"; } + + virtual void updateShapeFromElement() OVERRIDE; + virtual bool isShapeEmpty() const OVERRIDE { return m_usePathFallback ? RenderSVGShape::isShapeEmpty() : m_fillBoundingBox.isEmpty(); } + virtual void fillShape(GraphicsContext*) const OVERRIDE; + virtual void strokeShape(GraphicsContext*) const OVERRIDE; + virtual bool shapeDependentStrokeContains(const FloatPoint&) OVERRIDE; + virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const OVERRIDE; private: FloatRect m_innerStrokeRect; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResource.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResource.cpp index 4dd3ae01c90..0c67bc8d070 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResource.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResource.cpp @@ -24,8 +24,8 @@ #include "core/rendering/svg/RenderSVGResource.h" -#include "core/frame/Frame.h" #include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/rendering/svg/RenderSVGResourceClipper.h" #include "core/rendering/svg/RenderSVGResourceFilter.h" #include "core/rendering/svg/RenderSVGResourceMasker.h" @@ -35,22 +35,25 @@ namespace WebCore { -static inline bool inheritColorFromParentStyleIfNeeded(RenderObject* object, bool applyToFill, Color& color) +static inline bool inheritColorFromParentStyle(RenderObject* object, bool applyToFill, Color& color) { - if (color.isValid()) - return true; if (!object->parent() || !object->parent()->style()) return false; const SVGRenderStyle* parentSVGStyle = object->parent()->style()->svgStyle(); + SVGPaint::SVGPaintType paintType = applyToFill ? parentSVGStyle->fillPaintType() : parentSVGStyle->strokePaintType(); + if (paintType != SVGPaint::SVG_PAINTTYPE_RGBCOLOR && paintType != SVGPaint::SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR) + return false; color = applyToFill ? parentSVGStyle->fillPaintColor() : parentSVGStyle->strokePaintColor(); return true; } -static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode mode, RenderObject* object, const RenderStyle* style, Color& fallbackColor) +static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode mode, RenderObject* object, const RenderStyle* style, bool& hasFallback) { ASSERT(object); ASSERT(style); + hasFallback = false; + // If we have no style at all, ignore it. const SVGRenderStyle* svgStyle = style->svgStyle(); if (!svgStyle) @@ -78,10 +81,10 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m bool applyToFill = mode == ApplyToFillMode; SVGPaint::SVGPaintType paintType = applyToFill ? svgStyle->fillPaintType() : svgStyle->strokePaintType(); - if (paintType == SVGPaint::SVG_PAINTTYPE_NONE) - return 0; + ASSERT(paintType != SVGPaint::SVG_PAINTTYPE_NONE); Color color; + bool hasColor = false; switch (paintType) { case SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR: case SVGPaint::SVG_PAINTTYPE_RGBCOLOR: @@ -90,6 +93,7 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR: case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR: color = applyToFill ? svgStyle->fillPaintColor() : svgStyle->strokePaintColor(); + hasColor = true; default: break; } @@ -101,15 +105,15 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m // For SVG_PAINTTYPE_CURRENTCOLOR, 'color' already contains the 'visitedColor'. if (visitedPaintType < SVGPaint::SVG_PAINTTYPE_URI_NONE && visitedPaintType != SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) { const Color& visitedColor = applyToFill ? svgStyle->visitedLinkFillPaintColor() : svgStyle->visitedLinkStrokePaintColor(); - if (visitedColor.isValid()) - color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha()); + color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha()); + hasColor = true; } } // If the primary resource is just a color, return immediately. RenderSVGResourceSolidColor* colorResource = RenderSVGResource::sharedSolidPaintingResource(); if (paintType < SVGPaint::SVG_PAINTTYPE_URI_NONE) { - if (!inheritColorFromParentStyleIfNeeded(object, applyToFill, color)) + if (!hasColor && !inheritColorFromParentStyle(object, applyToFill, color)) return 0; colorResource->setColor(color); @@ -119,7 +123,7 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m // If no resources are associated with the given renderer, return the color resource. SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object); if (!resources) { - if (paintType == SVGPaint::SVG_PAINTTYPE_URI_NONE || !inheritColorFromParentStyleIfNeeded(object, applyToFill, color)) + if (paintType == SVGPaint::SVG_PAINTTYPE_URI_NONE || (!hasColor && !inheritColorFromParentStyle(object, applyToFill, color))) return 0; colorResource->setColor(color); @@ -129,7 +133,7 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m // If the requested resource is not available, return the color resource. RenderSVGResource* uriResource = mode == ApplyToFillMode ? resources->fill() : resources->stroke(); if (!uriResource) { - if (!inheritColorFromParentStyleIfNeeded(object, applyToFill, color)) + if (!hasColor && !inheritColorFromParentStyle(object, applyToFill, color)) return 0; colorResource->setColor(color); @@ -137,19 +141,22 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m } // The paint server resource exists, though it may be invalid (pattern with width/height=0). Pass the fallback color to our caller - // so it can use the solid color painting resource, if applyResource() on the URI resource failed. - fallbackColor = color; + // via sharedSolidPaintingResource so it can use the solid color painting resource, if applyResource() on the URI resource failed. + if (hasColor) { + colorResource->setColor(color); + hasFallback = true; + } return uriResource; } -RenderSVGResource* RenderSVGResource::fillPaintingResource(RenderObject* object, const RenderStyle* style, Color& fallbackColor) +RenderSVGResource* RenderSVGResource::fillPaintingResource(RenderObject* object, const RenderStyle* style, bool& hasFallback) { - return requestPaintingResource(ApplyToFillMode, object, style, fallbackColor); + return requestPaintingResource(ApplyToFillMode, object, style, hasFallback); } -RenderSVGResource* RenderSVGResource::strokePaintingResource(RenderObject* object, const RenderStyle* style, Color& fallbackColor) +RenderSVGResource* RenderSVGResource::strokePaintingResource(RenderObject* object, const RenderStyle* style, bool& hasFallback) { - return requestPaintingResource(ApplyToStrokeMode, object, style, fallbackColor); + return requestPaintingResource(ApplyToStrokeMode, object, style, hasFallback); } RenderSVGResourceSolidColor* RenderSVGResource::sharedSolidPaintingResource() @@ -176,13 +183,28 @@ static inline void removeFromCacheAndInvalidateDependencies(RenderObject* object if (!object->node() || !object->node()->isSVGElement()) return; - HashSet<SVGElement*>* dependencies = object->document().accessSVGExtensions()->setOfElementsReferencingTarget(toSVGElement(object->node())); + SVGElementSet* dependencies = object->document().accessSVGExtensions().setOfElementsReferencingTarget(toSVGElement(object->node())); if (!dependencies) return; - HashSet<SVGElement*>::iterator end = dependencies->end(); - for (HashSet<SVGElement*>::iterator it = dependencies->begin(); it != end; ++it) { - if (RenderObject* renderer = (*it)->renderer()) + + // We allow cycles in SVGDocumentExtensions reference sets in order to avoid expensive + // reference graph adjustments on changes, so we need to break possible cycles here. + // This strong reference is safe, as it is guaranteed that this set will be emptied + // at the end of recursion. + typedef WillBeHeapHashSet<RawPtrWillBeMember<SVGElement> > SVGElementSet; + DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<SVGElementSet>, invalidatingDependencies, (adoptPtrWillBeNoop(new SVGElementSet))); + + SVGElementSet::iterator end = dependencies->end(); + for (SVGElementSet::iterator it = dependencies->begin(); it != end; ++it) { + if (RenderObject* renderer = (*it)->renderer()) { + if (UNLIKELY(!invalidatingDependencies->add(*it).isNewEntry)) { + // Reference cycle: we are in process of invalidating this dependant. + continue; + } + RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, needsLayout); + invalidatingDependencies->remove(*it); + } } } @@ -192,7 +214,7 @@ void RenderSVGResource::markForLayoutAndParentResourceInvalidation(RenderObject* ASSERT(object->node()); if (needsLayout && !object->documentBeingDestroyed()) - object->setNeedsLayout(); + object->setNeedsLayoutAndFullPaintInvalidation(); removeFromCacheAndInvalidateDependencies(object, needsLayout); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResource.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResource.h index 676562dd01c..d1d3a89926b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResource.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResource.h @@ -43,9 +43,8 @@ enum RenderSVGResourceMode { ApplyToStrokeMode = 1 << 2, ApplyToTextMode = 1 << 3 // used in combination with ApplyTo{Fill|Stroke}Mode }; +typedef unsigned RenderSVGResourceModeFlags; -class Color; -class FloatRect; class GraphicsContext; class Path; class RenderObject; @@ -75,8 +74,9 @@ public: } // Helper utilities used in the render tree to access resources used for painting shapes/text (gradients & patterns & solid colors only) - static RenderSVGResource* fillPaintingResource(RenderObject*, const RenderStyle*, Color& fallbackColor); - static RenderSVGResource* strokePaintingResource(RenderObject*, const RenderStyle*, Color& fallbackColor); + // If hasFallback gets set to true, the sharedSolidPaintingResource is set to a fallback color. + static RenderSVGResource* fillPaintingResource(RenderObject*, const RenderStyle*, bool& hasFallback); + static RenderSVGResource* strokePaintingResource(RenderObject*, const RenderStyle*, bool& hasFallback); static RenderSVGResourceSolidColor* sharedSolidPaintingResource(); static void markForLayoutAndParentResourceInvalidation(RenderObject*, bool needsLayout = true); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceClipper.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceClipper.cpp index b98db0f7c86..62db92f8c1a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceClipper.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceClipper.cpp @@ -24,15 +24,16 @@ #include "core/rendering/svg/RenderSVGResourceClipper.h" -#include "RuntimeEnabledFeatures.h" -#include "SVGNames.h" -#include "core/frame/Frame.h" +#include "core/SVGNames.h" #include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/rendering/HitTestResult.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGRenderingContext.h" #include "core/rendering/svg/SVGResources.h" #include "core/rendering/svg/SVGResourcesCache.h" #include "core/svg/SVGUseElement.h" +#include "platform/RuntimeEnabledFeatures.h" #include "platform/graphics/DisplayList.h" #include "platform/graphics/GraphicsContextStateSaver.h" #include "wtf/TemporaryChange.h" @@ -78,7 +79,7 @@ bool RenderSVGResourceClipper::applyStatefulResource(RenderObject* object, Graph clearInvalidationMask(); - return applyClippingToContext(object, object->objectBoundingBox(), object->repaintRectInLocalCoordinates(), context, clipperContext); + return applyClippingToContext(object, object->objectBoundingBox(), object->paintInvalidationRectInLocalCoordinates(), context, clipperContext); } bool RenderSVGResourceClipper::tryPathOnlyClipping(GraphicsContext* context, @@ -89,16 +90,16 @@ bool RenderSVGResourceClipper::tryPathOnlyClipping(GraphicsContext* context, WindRule clipRule = RULE_NONZERO; Path clipPath = Path(); - for (Node* childNode = element()->firstChild(); childNode; childNode = childNode->nextSibling()) { - RenderObject* renderer = childNode->renderer(); + for (Element* childElement = ElementTraversal::firstWithin(*element()); childElement; childElement = ElementTraversal::nextSibling(*childElement)) { + RenderObject* renderer = childElement->renderer(); if (!renderer) continue; // Only shapes or paths are supported for direct clipping. We need to fallback to masking for texts. if (renderer->isSVGText()) return false; - if (!childNode->isSVGElement() || !toSVGElement(childNode)->isSVGGraphicsElement()) + if (!childElement->isSVGElement() || !toSVGElement(childElement)->isSVGGraphicsElement()) continue; - SVGGraphicsElement* styled = toSVGGraphicsElement(childNode); + SVGGraphicsElement* styled = toSVGGraphicsElement(childElement); RenderStyle* style = renderer->style(); if (!style || style->display() == NONE || style->visibility() != VISIBLE) continue; @@ -127,7 +128,7 @@ bool RenderSVGResourceClipper::tryPathOnlyClipping(GraphicsContext* context, } } // Only one visible shape/path was found. Directly continue clipping and transform the content to userspace if necessary. - if (toSVGClipPathElement(element())->clipPathUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + if (toSVGClipPathElement(element())->clipPathUnits()->currentValue()->enumValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { AffineTransform transform; transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); @@ -148,7 +149,6 @@ bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* target, cons const FloatRect& repaintRect, GraphicsContext* context, ClipperContext& clipperContext) { ASSERT(target); - ASSERT(target->node()); ASSERT(context); ASSERT(clipperContext.state == ClipperContext::NotAppliedState); ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout()); @@ -161,8 +161,8 @@ bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* target, cons // When drawing a clip for non-SVG elements, the CTM does not include the zoom factor. // In this case, we need to apply the zoom scale explicitly - but only for clips with // userSpaceOnUse units (the zoom is accounted for objectBoundingBox-resolved lengths). - if (!target->node()->isSVGElement() - && toSVGClipPathElement(element())->clipPathUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) { + if (!target->isSVG() + && toSVGClipPathElement(element())->clipPathUnits()->currentValue()->enumValue() == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) { ASSERT(style()); animatedLocalTransform.scale(style()->effectiveZoom()); } @@ -238,7 +238,7 @@ void RenderSVGResourceClipper::drawClipMaskContent(GraphicsContext* context, con ASSERT(context); AffineTransform contentTransformation; - SVGUnitTypes::SVGUnitType contentUnits = toSVGClipPathElement(element())->clipPathUnitsCurrentValue(); + SVGUnitTypes::SVGUnitType contentUnits = toSVGClipPathElement(element())->clipPathUnits()->currentValue()->enumValue(); if (contentUnits == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y()); contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height()); @@ -258,7 +258,10 @@ PassRefPtr<DisplayList> RenderSVGResourceClipper::asDisplayList(GraphicsContext* ASSERT(context); ASSERT(frame()); - context->beginRecording(repaintRectInLocalCoordinates()); + // Using strokeBoundingBox (instead of paintInvalidationRectInLocalCoordinates) to avoid the intersection + // with local clips/mask, which may yield incorrect results when mixing objectBoundingBox and + // userSpaceOnUse units (http://crbug.com/294900). + context->beginRecording(strokeBoundingBox()); // Switch to a paint behavior where all children of this <clipPath> will be rendered using special constraints: // - fill-opacity/stroke-opacity/opacity set to 1 @@ -268,9 +271,9 @@ PassRefPtr<DisplayList> RenderSVGResourceClipper::asDisplayList(GraphicsContext* PaintBehavior oldBehavior = frame()->view()->paintBehavior(); frame()->view()->setPaintBehavior(oldBehavior | PaintBehaviorRenderingSVGMask); - for (Node* childNode = element()->firstChild(); childNode; childNode = childNode->nextSibling()) { - RenderObject* renderer = childNode->renderer(); - if (!childNode->isSVGElement() || !renderer) + for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) { + RenderObject* renderer = childElement->renderer(); + if (!renderer) continue; RenderStyle* style = renderer->style(); @@ -278,13 +281,13 @@ PassRefPtr<DisplayList> RenderSVGResourceClipper::asDisplayList(GraphicsContext* continue; WindRule newClipRule = style->svgStyle()->clipRule(); - bool isUseElement = childNode->hasTagName(SVGNames::useTag); + bool isUseElement = isSVGUseElement(*childElement); if (isUseElement) { - SVGUseElement* useElement = toSVGUseElement(childNode); - renderer = useElement->rendererClipChild(); + SVGUseElement& useElement = toSVGUseElement(*childElement); + renderer = useElement.rendererClipChild(); if (!renderer) continue; - if (!useElement->hasAttribute(SVGNames::clip_ruleAttr)) + if (!useElement.hasAttribute(SVGNames::clip_ruleAttr)) newClipRule = renderer->style()->svgStyle()->clipRule(); } @@ -295,7 +298,7 @@ PassRefPtr<DisplayList> RenderSVGResourceClipper::asDisplayList(GraphicsContext* context->setFillRule(newClipRule); if (isUseElement) - renderer = childNode->renderer(); + renderer = childElement->renderer(); SVGRenderingContext::renderSubtree(context, renderer, contentTransformation); } @@ -308,16 +311,16 @@ PassRefPtr<DisplayList> RenderSVGResourceClipper::asDisplayList(GraphicsContext* void RenderSVGResourceClipper::calculateClipContentRepaintRect() { // This is a rough heuristic to appraise the clip size and doesn't consider clip on clip. - for (Node* childNode = element()->firstChild(); childNode; childNode = childNode->nextSibling()) { - RenderObject* renderer = childNode->renderer(); - if (!childNode->isSVGElement() || !renderer) + for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) { + RenderObject* renderer = childElement->renderer(); + if (!renderer) continue; - if (!renderer->isSVGShape() && !renderer->isSVGText() && !childNode->hasTagName(SVGNames::useTag)) + if (!renderer->isSVGShape() && !renderer->isSVGText() && !isSVGUseElement(*childElement)) continue; RenderStyle* style = renderer->style(); if (!style || style->display() == NONE || style->visibility() != VISIBLE) continue; - m_clipBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates())); + m_clipBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->paintInvalidationRectInLocalCoordinates())); } m_clipBoundaries = toSVGClipPathElement(element())->animatedLocalTransform().mapRect(m_clipBoundaries); } @@ -329,7 +332,7 @@ bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundin return false; SVGClipPathElement* clipPathElement = toSVGClipPathElement(element()); - if (clipPathElement->clipPathUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + if (clipPathElement->clipPathUnits()->currentValue()->enumValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { AffineTransform transform; transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); @@ -338,11 +341,11 @@ bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundin point = clipPathElement->animatedLocalTransform().inverse().mapPoint(point); - for (Node* childNode = element()->firstChild(); childNode; childNode = childNode->nextSibling()) { - RenderObject* renderer = childNode->renderer(); - if (!childNode->isSVGElement() || !renderer) + for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) { + RenderObject* renderer = childElement->renderer(); + if (!renderer) continue; - if (!renderer->isSVGShape() && !renderer->isSVGText() && !childNode->hasTagName(SVGNames::useTag)) + if (!renderer->isSVGShape() && !renderer->isSVGText() && !isSVGUseElement(*childElement)) continue; IntPoint hitPoint; HitTestResult result(hitPoint); @@ -353,7 +356,7 @@ bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundin return false; } -FloatRect RenderSVGResourceClipper::resourceBoundingBox(RenderObject* object) +FloatRect RenderSVGResourceClipper::resourceBoundingBox(const RenderObject* object) { // Resource was not layouted yet. Give back the boundingBox of the object. if (selfNeedsLayout()) @@ -362,7 +365,7 @@ FloatRect RenderSVGResourceClipper::resourceBoundingBox(RenderObject* object) if (m_clipBoundaries.isEmpty()) calculateClipContentRepaintRect(); - if (toSVGClipPathElement(element())->clipPathUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + if (toSVGClipPathElement(element())->clipPathUnits()->currentValue()->enumValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { FloatRect objectBoundingBox = object->objectBoundingBox(); AffineTransform transform; transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceClipper.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceClipper.h index ae89b1e3df5..75a805859ff 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceClipper.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceClipper.h @@ -45,13 +45,13 @@ public: explicit RenderSVGResourceClipper(SVGClipPathElement*); virtual ~RenderSVGResourceClipper(); - virtual const char* renderName() const { return "RenderSVGResourceClipper"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGResourceClipper"; } - virtual void removeAllClientsFromCache(bool markForInvalidation = true); - virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); + virtual void removeAllClientsFromCache(bool markForInvalidation = true) OVERRIDE; + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true) OVERRIDE; - virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode) OVERRIDE FINAL; - virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short, const Path*, const RenderSVGShape*) OVERRIDE FINAL; + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode) OVERRIDE; + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short, const Path*, const RenderSVGShape*) OVERRIDE; // FIXME: Filters are also stateful resources that could benefit from having their state managed // on the caller stack instead of the current hashmap. We should look at refactoring these @@ -64,13 +64,13 @@ public: // FIXME: We made applyClippingToContext public because we cannot call applyResource on HTML elements (it asserts on RenderObject::objectBoundingBox) bool applyClippingToContext(RenderObject*, const FloatRect&, const FloatRect&, GraphicsContext*, ClipperContext&); - FloatRect resourceBoundingBox(RenderObject*); + FloatRect resourceBoundingBox(const RenderObject*); - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; } bool hitTestClipContent(const FloatRect&, const FloatPoint&); - SVGUnitTypes::SVGUnitType clipPathUnits() const { return toSVGClipPathElement(element())->clipPathUnitsCurrentValue(); } + SVGUnitTypes::SVGUnitType clipPathUnits() const { return toSVGClipPathElement(element())->clipPathUnits()->currentValue()->enumValue(); } static const RenderSVGResourceType s_resourceType; private: diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceContainer.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceContainer.cpp index 55405a77a08..8434f4fe4ee 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceContainer.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceContainer.cpp @@ -21,7 +21,6 @@ #include "core/rendering/svg/RenderSVGResourceContainer.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderView.h" #include "core/rendering/svg/SVGRenderingContext.h" @@ -32,7 +31,7 @@ namespace WebCore { -static inline SVGDocumentExtensions* svgExtensionsFromElement(SVGElement* element) +static inline SVGDocumentExtensions& svgExtensionsFromElement(SVGElement* element) { ASSERT(element); return element->document().accessSVGExtensions(); @@ -51,7 +50,7 @@ RenderSVGResourceContainer::RenderSVGResourceContainer(SVGElement* node) RenderSVGResourceContainer::~RenderSVGResourceContainer() { if (m_registered) - svgExtensionsFromElement(element())->removeResource(m_id); + svgExtensionsFromElement(element()).removeResource(m_id); } void RenderSVGResourceContainer::layout() @@ -62,7 +61,6 @@ void RenderSVGResourceContainer::layout() if (m_isInLayout) return; - LayoutRectRecorder recorder(*this); TemporaryChange<bool> inLayoutChange(m_isInLayout, true); RenderSVGHiddenContainer::layout(); @@ -92,8 +90,8 @@ void RenderSVGResourceContainer::idChanged() removeAllClientsFromCache(); // Remove old id, that is guaranteed to be present in cache. - SVGDocumentExtensions* extensions = svgExtensionsFromElement(element()); - extensions->removeResource(m_id); + SVGDocumentExtensions& extensions = svgExtensionsFromElement(element()); + extensions.removeResource(m_id); m_id = element()->getIdAttribute(); registerResource(); @@ -150,10 +148,10 @@ void RenderSVGResourceContainer::markClientForInvalidation(RenderObject* client, break; case RepaintInvalidation: if (client->view()) { - if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && frameView()->isInLayout()) - client->setShouldDoFullRepaintAfterLayout(true); + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && frameView()->isInPerformLayout()) + client->setShouldDoFullPaintInvalidationAfterLayout(true); else - client->repaint(); + client->paintInvalidationForWholeRenderer(); } break; case ParentOnlyInvalidation: @@ -202,7 +200,7 @@ void RenderSVGResourceContainer::invalidateCacheAndMarkForLayout(SubtreeLayoutSc if (selfNeedsLayout()) return; - setNeedsLayout(MarkContainingBlockChain, layoutScope); + setNeedsLayoutAndFullPaintInvalidation(MarkContainingBlockChain, layoutScope); if (everHadLayout()) removeAllClientsFromCache(); @@ -210,33 +208,36 @@ void RenderSVGResourceContainer::invalidateCacheAndMarkForLayout(SubtreeLayoutSc void RenderSVGResourceContainer::registerResource() { - SVGDocumentExtensions* extensions = svgExtensionsFromElement(element()); - if (!extensions->hasPendingResource(m_id)) { - extensions->addResource(m_id, this); + SVGDocumentExtensions& extensions = svgExtensionsFromElement(element()); + if (!extensions.hasPendingResource(m_id)) { + extensions.addResource(m_id, this); return; } - OwnPtr<SVGDocumentExtensions::SVGPendingElements> clients(extensions->removePendingResource(m_id)); + OwnPtr<SVGDocumentExtensions::SVGPendingElements> clients(extensions.removePendingResource(m_id)); // Cache us with the new id. - extensions->addResource(m_id, this); + extensions.addResource(m_id, this); // Update cached resources of pending clients. const SVGDocumentExtensions::SVGPendingElements::const_iterator end = clients->end(); for (SVGDocumentExtensions::SVGPendingElements::const_iterator it = clients->begin(); it != end; ++it) { ASSERT((*it)->hasPendingResources()); - extensions->clearHasPendingResourcesIfPossible(*it); + extensions.clearHasPendingResourcesIfPossible(*it); RenderObject* renderer = (*it)->renderer(); if (!renderer) continue; - SVGResourcesCache::clientStyleChanged(renderer, StyleDifferenceLayout, renderer->style()); - renderer->setNeedsLayout(); + + StyleDifference diff; + diff.setNeedsFullLayout(); + SVGResourcesCache::clientStyleChanged(renderer, diff, renderer->style()); + renderer->setNeedsLayoutAndFullPaintInvalidation(); } } -bool RenderSVGResourceContainer::shouldTransformOnTextPainting(RenderObject* object, AffineTransform& resourceTransform) +static bool shouldTransformOnTextPainting(RenderObject* object, AffineTransform& resourceTransform) { - ASSERT_UNUSED(object, object); + ASSERT(object); // This method should only be called for RenderObjects that deal with text rendering. Cmp. RenderObject.h's is*() methods. ASSERT(object->isSVGText() || object->isSVGTextPath() || object->isSVGInline()); @@ -251,6 +252,26 @@ bool RenderSVGResourceContainer::shouldTransformOnTextPainting(RenderObject* obj return true; } +AffineTransform RenderSVGResourceContainer::computeResourceSpaceTransform(RenderObject* object, const AffineTransform& baseTransform, const SVGRenderStyle* svgStyle, unsigned short resourceMode) +{ + AffineTransform computedSpaceTransform = baseTransform; + if (resourceMode & ApplyToTextMode) { + // Depending on the font scaling factor, we may need to apply an + // additional transform (scale-factor) the paintserver, since text + // painting removes the scale factor from the context. (See + // SVGInlineTextBox::paintTextWithShadows.) + AffineTransform additionalTextTransformation; + if (shouldTransformOnTextPainting(object, additionalTextTransformation)) + computedSpaceTransform = additionalTextTransformation * computedSpaceTransform; + } + if (resourceMode & ApplyToStrokeMode) { + // Non-scaling stroke needs to reset the transform back to the host transform. + if (svgStyle->vectorEffect() == VE_NON_SCALING_STROKE) + computedSpaceTransform = transformOnNonScalingStroke(object, computedSpaceTransform); + } + return computedSpaceTransform; +} + // FIXME: This does not belong here. AffineTransform RenderSVGResourceContainer::transformOnNonScalingStroke(RenderObject* object, const AffineTransform& resourceTransform) { diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceContainer.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceContainer.h index 71d3c6f0cf1..52b50c394a3 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceContainer.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceContainer.h @@ -33,12 +33,11 @@ public: explicit RenderSVGResourceContainer(SVGElement*); virtual ~RenderSVGResourceContainer(); - virtual void layout(); + virtual void layout() OVERRIDE; virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE FINAL; virtual bool isSVGResourceContainer() const OVERRIDE FINAL { return true; } - static bool shouldTransformOnTextPainting(RenderObject*, AffineTransform&); static AffineTransform transformOnNonScalingStroke(RenderObject*, const AffineTransform& resourceTransform); void idChanged(); @@ -64,6 +63,8 @@ protected: void clearInvalidationMask() { m_invalidationMask = 0; } + static AffineTransform computeResourceSpaceTransform(RenderObject*, const AffineTransform& baseTransform, const SVGRenderStyle*, unsigned short resourceMode); + bool m_isInLayout; private: @@ -86,21 +87,21 @@ private: HashSet<RenderLayer*> m_clientLayers; }; -inline RenderSVGResourceContainer* getRenderSVGResourceContainerById(Document& document, const AtomicString& id) +inline RenderSVGResourceContainer* getRenderSVGResourceContainerById(TreeScope& treeScope, const AtomicString& id) { if (id.isEmpty()) return 0; - if (RenderSVGResourceContainer* renderResource = document.accessSVGExtensions()->resourceById(id)) + if (RenderSVGResourceContainer* renderResource = treeScope.document().accessSVGExtensions().resourceById(id)) return renderResource; return 0; } template<typename Renderer> -Renderer* getRenderSVGResourceById(Document& document, const AtomicString& id) +Renderer* getRenderSVGResourceById(TreeScope& treeScope, const AtomicString& id) { - if (RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id)) + if (RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(treeScope, id)) return container->cast<Renderer>(); return 0; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.cpp index 840c563c4c2..80f0a30a0c2 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.cpp @@ -30,9 +30,9 @@ #include "core/rendering/svg/SVGRenderingContext.h" #include "core/svg/SVGFilterPrimitiveStandardAttributes.h" #include "platform/graphics/UnacceleratedImageBufferSurface.h" +#include "platform/graphics/filters/SkiaImageFilterBuilder.h" #include "platform/graphics/filters/SourceAlpha.h" #include "platform/graphics/filters/SourceGraphic.h" -#include "platform/graphics/gpu/AcceleratedImageBufferSurface.h" using namespace std; @@ -50,6 +50,11 @@ RenderSVGResourceFilter::~RenderSVGResourceFilter() m_filter.clear(); } +bool RenderSVGResourceFilter::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + return child->isSVGResourceFilterPrimitive(); +} + void RenderSVGResourceFilter::removeAllClientsFromCache(bool markForInvalidation) { m_filter.clear(); @@ -77,11 +82,7 @@ PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter* // Add effects to the builder RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(SourceGraphic::create(filter), SourceAlpha::create(filter)); - for (Node* node = filterElement->firstChild(); node; node = node->nextSibling()) { - if (!node->isSVGElement()) - continue; - - SVGElement* element = toSVGElement(node); + for (SVGElement* element = Traversal<SVGElement>::firstChild(*filterElement); element; element = Traversal<SVGElement>::nextSibling(*element)) { if (!element->isFilterEffect() || !element->renderer()) continue; @@ -89,46 +90,40 @@ PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter* RefPtr<FilterEffect> effect = effectElement->build(builder.get(), filter); if (!effect) { builder->clearEffects(); - return 0; + return nullptr; } builder->appendEffectToEffectReferences(effect, effectElement->renderer()); effectElement->setStandardAttributes(effect.get()); - effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnitsCurrentValue(), targetBoundingBox)); + effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnits()->currentValue()->enumValue(), targetBoundingBox)); effect->setOperatingColorSpace( effectElement->renderer()->style()->svgStyle()->colorInterpolationFilters() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB); - builder->add(effectElement->resultCurrentValue(), effect); + builder->add(AtomicString(effectElement->result()->currentValue()->value()), effect); } return builder.release(); } -bool RenderSVGResourceFilter::fitsInMaximumImageSize(const FloatSize& size, FloatSize& scale) +void RenderSVGResourceFilter::adjustScaleForMaximumImageSize(const FloatSize& size, FloatSize& filterScale) { - bool matchesFilterSize = true; - if (size.width() > kMaxFilterSize) { - scale.setWidth(scale.width() * kMaxFilterSize / size.width()); - matchesFilterSize = false; - } - if (size.height() > kMaxFilterSize) { - scale.setHeight(scale.height() * kMaxFilterSize / size.height()); - matchesFilterSize = false; - } + FloatSize scaledSize(size); + scaledSize.scale(filterScale.width(), filterScale.height()); + float scaledArea = scaledSize.width() * scaledSize.height(); + + if (scaledArea <= FilterEffect::maxFilterArea()) + return; - return matchesFilterSize; + // If area of scaled size is bigger than the upper limit, adjust the scale + // to fit. + filterScale.scale(sqrt(FilterEffect::maxFilterArea() / scaledArea)); } -static bool createImageBuffer(const FloatRect& targetRect, const AffineTransform& absoluteTransform, - OwnPtr<ImageBuffer>& imageBuffer, bool accelerated) +static bool createImageBuffer(const Filter* filter, OwnPtr<ImageBuffer>& imageBuffer) { - IntRect paintRect = SVGRenderingContext::calculateImageBufferRect(targetRect, absoluteTransform); + IntRect paintRect = filter->sourceImageRect(); // Don't create empty ImageBuffers. if (paintRect.isEmpty()) return false; - OwnPtr<ImageBufferSurface> surface; - if (accelerated) - surface = adoptPtr(new AcceleratedImageBufferSurface(paintRect.size())); - if (!accelerated || !surface->isValid()) - surface = adoptPtr(new UnacceleratedImageBufferSurface(paintRect.size())); + OwnPtr<ImageBufferSurface> surface = adoptPtr(new UnacceleratedImageBufferSurface(paintRect.size())); if (!surface->isValid()) return false; OwnPtr<ImageBuffer> image = ImageBuffer::create(surface.release()); @@ -137,12 +132,71 @@ static bool createImageBuffer(const FloatRect& targetRect, const AffineTransform ASSERT(imageContext); imageContext->translate(-paintRect.x(), -paintRect.y()); - imageContext->concatCTM(absoluteTransform); - + imageContext->concatCTM(filter->absoluteTransform()); imageBuffer = image.release(); return true; } +static void beginDeferredFilter(GraphicsContext* context, FilterData* filterData, SVGFilterElement* filterElement) +{ + SkiaImageFilterBuilder builder(context); + RefPtr<ImageFilter> imageFilter = builder.build(filterData->builder->lastEffect(), ColorSpaceDeviceRGB); + // FIXME: Remove the cache when impl-size painting is enabled on every platform and the non impl-side painting path is removed + if (!context->isRecordingCanvas()) // Recording canvases do not use the cache + filterData->filter->enableCache(); + FloatRect boundaries = enclosingIntRect(filterData->boundaries); + context->save(); + float scaledArea = boundaries.width() * boundaries.height(); + + // If area of scaled size is bigger than the upper limit, adjust the scale + // to fit. + if (scaledArea > FilterEffect::maxFilterArea()) { + float scale = sqrtf(FilterEffect::maxFilterArea() / scaledArea); + context->scale(scale, scale); + } + // Clip drawing of filtered image to primitive boundaries. + context->clipRect(boundaries); + if (filterElement->hasAttribute(SVGNames::filterResAttr)) { + // Get boundaries in device coords. + // FIXME: See crbug.com/382491. Is the use of getCTM OK here, given it does not include device + // zoom or High DPI adjustments? + FloatSize size = context->getCTM().mapSize(boundaries.size()); + // Compute the scale amount required so that the resulting offscreen is exactly filterResX by filterResY pixels. + float filterResScaleX = filterElement->filterResX()->currentValue()->value() / size.width(); + float filterResScaleY = filterElement->filterResY()->currentValue()->value() / size.height(); + // Scale the CTM so the primitive is drawn to filterRes. + context->scale(filterResScaleX, filterResScaleY); + // Create a resize filter with the inverse scale. + AffineTransform resizeMatrix; + resizeMatrix.scale(1 / filterResScaleX, 1 / filterResScaleY); + imageFilter = builder.buildTransform(resizeMatrix, imageFilter.get()); + } + // If the CTM contains rotation or shearing, apply the filter to + // the unsheared/unrotated matrix, and do the shearing/rotation + // as a final pass. + AffineTransform ctm = context->getCTM(); + if (ctm.b() || ctm.c()) { + AffineTransform scaleAndTranslate; + scaleAndTranslate.translate(ctm.e(), ctm.f()); + scaleAndTranslate.scale(ctm.xScale(), ctm.yScale()); + ASSERT(scaleAndTranslate.isInvertible()); + AffineTransform shearAndRotate = scaleAndTranslate.inverse(); + shearAndRotate.multiply(ctm); + context->setCTM(scaleAndTranslate); + imageFilter = builder.buildTransform(shearAndRotate, imageFilter.get()); + } + context->beginLayer(1, CompositeSourceOver, &boundaries, ColorFilterNone, imageFilter.get()); +} + +static void endDeferredFilter(GraphicsContext* context, FilterData* filterData) +{ + context->endLayer(); + context->restore(); + // FIXME: Remove the cache when impl-size painting is enabled on every platform and the non impl-side painting path is removed + if (!context->isRecordingCanvas()) // Recording canvases do not use the cache + filterData->filter->disableCache(); +} + bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) { ASSERT(object); @@ -151,10 +205,16 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, clearInvalidationMask(); + bool deferredFiltersEnabled = object->document().settings()->deferredFiltersEnabled(); if (m_filter.contains(object)) { FilterData* filterData = m_filter.get(object); if (filterData->state == FilterData::PaintingSource || filterData->state == FilterData::Applying) filterData->state = FilterData::CycleDetected; + if (deferredFiltersEnabled && filterData->state == FilterData::Built) { + SVGFilterElement* filterElement = toSVGFilterElement(element()); + beginDeferredFilter(context, filterData, filterElement); + return true; + } return false; // Already built, or we're in a cycle, or we're marked for removal. Regardless, just do nothing more now. } @@ -162,64 +222,65 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, FloatRect targetBoundingBox = object->objectBoundingBox(); SVGFilterElement* filterElement = toSVGFilterElement(element()); - filterData->boundaries = SVGLengthContext::resolveRectangle<SVGFilterElement>(filterElement, filterElement->filterUnitsCurrentValue(), targetBoundingBox); + filterData->boundaries = SVGLengthContext::resolveRectangle<SVGFilterElement>(filterElement, filterElement->filterUnits()->currentValue()->enumValue(), targetBoundingBox); if (filterData->boundaries.isEmpty()) return false; // Determine absolute transformation matrix for filter. AffineTransform absoluteTransform; - SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform); + SVGRenderingContext::calculateDeviceSpaceTransformation(object, absoluteTransform); if (!absoluteTransform.isInvertible()) return false; - // Eliminate shear of the absolute transformation matrix, to be able to produce unsheared tile images for feTile. - filterData->shearFreeAbsoluteTransform = AffineTransform(absoluteTransform.xScale(), 0, 0, absoluteTransform.yScale(), 0, 0); + // Filters cannot handle a full transformation, only scales in each direction. + FloatSize filterScale; + + // Calculate the scale factor for the filter. + // Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion + if (filterElement->hasAttribute(SVGNames::filterResAttr)) { + // If resolution is specified, scale to match it. + filterScale = FloatSize( + filterElement->filterResX()->currentValue()->value() / filterData->boundaries.width(), + filterElement->filterResY()->currentValue()->value() / filterData->boundaries.height()); + } else { + // Otherwise, use the scale of the absolute transform. + filterScale = FloatSize(absoluteTransform.xScale(), absoluteTransform.yScale()); + } + // The size of the scaled filter boundaries shouldn't be bigger than kMaxFilterSize. + // Intermediate filters are limited by the filter boundaries so they can't be bigger than this. + adjustScaleForMaximumImageSize(filterData->boundaries.size(), filterScale); - // Determine absolute boundaries of the filter and the drawing region. - FloatRect absoluteFilterBoundaries = filterData->shearFreeAbsoluteTransform.mapRect(filterData->boundaries); filterData->drawingRegion = object->strokeBoundingBox(); filterData->drawingRegion.intersect(filterData->boundaries); - FloatRect absoluteDrawingRegion = filterData->shearFreeAbsoluteTransform.mapRect(filterData->drawingRegion); + FloatRect absoluteDrawingRegion = filterData->drawingRegion; + if (!deferredFiltersEnabled) + absoluteDrawingRegion.scale(filterScale.width(), filterScale.height()); + + IntRect intDrawingRegion = enclosingIntRect(absoluteDrawingRegion); // Create the SVGFilter object. - bool primitiveBoundingBoxMode = filterElement->primitiveUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; - filterData->filter = SVGFilter::create(filterData->shearFreeAbsoluteTransform, absoluteDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode); + bool primitiveBoundingBoxMode = filterElement->primitiveUnits()->currentValue()->enumValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; + filterData->shearFreeAbsoluteTransform = AffineTransform(); + if (!deferredFiltersEnabled) + filterData->shearFreeAbsoluteTransform.scale(filterScale.width(), filterScale.height()); + filterData->filter = SVGFilter::create(filterData->shearFreeAbsoluteTransform, intDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode); // Create all relevant filter primitives. filterData->builder = buildPrimitives(filterData->filter.get()); if (!filterData->builder) return false; - // Calculate the scale factor for the use of filterRes. - // Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion - FloatSize scale(1, 1); - if (filterElement->hasAttribute(SVGNames::filterResAttr)) { - scale.setWidth(filterElement->filterResXCurrentValue() / absoluteFilterBoundaries.width()); - scale.setHeight(filterElement->filterResYCurrentValue() / absoluteFilterBoundaries.height()); - } - - if (scale.isEmpty()) - return false; - - // Determine scale factor for filter. The size of intermediate ImageBuffers shouldn't be bigger than kMaxFilterSize. - FloatRect tempSourceRect = absoluteDrawingRegion; - tempSourceRect.scale(scale.width(), scale.height()); - fitsInMaximumImageSize(tempSourceRect.size(), scale); - - // Set the scale level in SVGFilter. - filterData->filter->setFilterResolution(scale); - FilterEffect* lastEffect = filterData->builder->lastEffect(); if (!lastEffect) return false; lastEffect->determineFilterPrimitiveSubregion(ClipToFilterRegion); - FloatRect subRegion = lastEffect->maxEffectRect(); - // At least one FilterEffect has a too big image size, - // recalculate the effect sizes with new scale factors. - if (!fitsInMaximumImageSize(subRegion.size(), scale)) { - filterData->filter->setFilterResolution(scale); - lastEffect->determineFilterPrimitiveSubregion(ClipToFilterRegion); + + if (deferredFiltersEnabled) { + FilterData* data = filterData.get(); + m_filter.set(object, filterData.release()); + beginDeferredFilter(context, data, filterElement); + return true; } // If the drawingRegion is empty, we have something like <g filter=".."/>. @@ -231,23 +292,14 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, return false; } - // Change the coordinate transformation applied to the filtered element to reflect the resolution of the filter. - AffineTransform effectiveTransform; - effectiveTransform.scale(scale.width(), scale.height()); - effectiveTransform.multiply(filterData->shearFreeAbsoluteTransform); - OwnPtr<ImageBuffer> sourceGraphic; - bool isAccelerated = object->document().settings()->acceleratedFiltersEnabled(); - if (!createImageBuffer(filterData->drawingRegion, effectiveTransform, sourceGraphic, isAccelerated)) { + if (!createImageBuffer(filterData->filter.get(), sourceGraphic)) { ASSERT(!m_filter.contains(object)); filterData->savedContext = context; m_filter.set(object, filterData.release()); return false; } - // Set the rendering mode from the page's settings. - filterData->filter->setIsAccelerated(isAccelerated); - GraphicsContext* sourceGraphicContext = sourceGraphic->context(); ASSERT(sourceGraphicContext); @@ -272,6 +324,12 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo if (!filterData) return; + if (object->document().settings()->deferredFiltersEnabled() && (filterData->state == FilterData::PaintingSource || filterData->state == FilterData::Built)) { + endDeferredFilter(context, filterData); + filterData->state = FilterData::Built; + return; + } + switch (filterData->state) { case FilterData::MarkedForRemoval: m_filter.remove(object); @@ -319,22 +377,16 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo ImageBuffer* resultImage = lastEffect->asImageBuffer(); if (resultImage) { - context->concatCTM(filterData->shearFreeAbsoluteTransform.inverse()); - - context->scale(FloatSize(1 / filterData->filter->filterResolution().width(), 1 / filterData->filter->filterResolution().height())); - context->drawImageBuffer(resultImage, lastEffect->absolutePaintRect()); - context->scale(filterData->filter->filterResolution()); - - context->concatCTM(filterData->shearFreeAbsoluteTransform); + context->drawImageBuffer(resultImage, filterData->filter->mapAbsoluteRectToLocalRect(lastEffect->absolutePaintRect())); } } filterData->sourceGraphicBuffer.clear(); } -FloatRect RenderSVGResourceFilter::resourceBoundingBox(RenderObject* object) +FloatRect RenderSVGResourceFilter::resourceBoundingBox(const RenderObject* object) { if (SVGFilterElement* element = toSVGFilterElement(this->element())) - return SVGLengthContext::resolveRectangle<SVGFilterElement>(element, element->filterUnitsCurrentValue(), object->objectBoundingBox()); + return SVGLengthContext::resolveRectangle<SVGFilterElement>(element, element->filterUnits()->currentValue()->enumValue(), object->objectBoundingBox()); return FloatRect(); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.h index 6455b039284..1c679130ccc 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.h @@ -60,30 +60,32 @@ public: explicit RenderSVGResourceFilter(SVGFilterElement*); virtual ~RenderSVGResourceFilter(); - virtual const char* renderName() const { return "RenderSVGResourceFilter"; } + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; + + virtual const char* renderName() const OVERRIDE { return "RenderSVGResourceFilter"; } virtual bool isSVGResourceFilter() const OVERRIDE { return true; } - virtual void removeAllClientsFromCache(bool markForInvalidation = true); - virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); + virtual void removeAllClientsFromCache(bool markForInvalidation = true) OVERRIDE; + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true) OVERRIDE; - virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); - virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*); + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode) OVERRIDE; + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*) OVERRIDE; - FloatRect resourceBoundingBox(RenderObject*); + FloatRect resourceBoundingBox(const RenderObject*); PassRefPtr<SVGFilterBuilder> buildPrimitives(SVGFilter*); - SVGUnitTypes::SVGUnitType filterUnits() const { return toSVGFilterElement(element())->filterUnitsCurrentValue(); } - SVGUnitTypes::SVGUnitType primitiveUnits() const { return toSVGFilterElement(element())->primitiveUnitsCurrentValue(); } + SVGUnitTypes::SVGUnitType filterUnits() const { return toSVGFilterElement(element())->filterUnits()->currentValue()->enumValue(); } + SVGUnitTypes::SVGUnitType primitiveUnits() const { return toSVGFilterElement(element())->primitiveUnits()->currentValue()->enumValue(); } void primitiveAttributeChanged(RenderObject*, const QualifiedName&); - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; } static const RenderSVGResourceType s_resourceType; FloatRect drawingRegion(RenderObject*) const; private: - bool fitsInMaximumImageSize(const FloatSize&, FloatSize&); + void adjustScaleForMaximumImageSize(const FloatSize&, FloatSize&); typedef HashMap<RenderObject*, OwnPtr<FilterData> > FilterMap; FilterMap m_filter; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilterPrimitive.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilterPrimitive.cpp index e34449d35ea..f7fce429304 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilterPrimitive.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilterPrimitive.cpp @@ -40,16 +40,17 @@ void RenderSVGResourceFilterPrimitive::styleDidChange(StyleDifference diff, cons return; ASSERT(filter->isSVGResourceFilter()); - if (diff == StyleDifferenceEqual || !oldStyle) + if (diff.hasNoChange() || !oldStyle) return; const SVGRenderStyle* newStyle = this->style()->svgStyle(); - if (element()->hasTagName(SVGNames::feFloodTag)) { + ASSERT(element()); + if (isSVGFEFloodElement(*element())) { if (newStyle->floodColor() != oldStyle->svgStyle()->floodColor()) toRenderSVGResourceFilter(filter)->primitiveAttributeChanged(this, SVGNames::flood_colorAttr); if (newStyle->floodOpacity() != oldStyle->svgStyle()->floodOpacity()) toRenderSVGResourceFilter(filter)->primitiveAttributeChanged(this, SVGNames::flood_opacityAttr); - } else if (element()->hasTagName(SVGNames::feDiffuseLightingTag) || element()->hasTagName(SVGNames::feSpecularLightingTag)) { + } else if (isSVGFEDiffuseLightingElement(*element()) || isSVGFESpecularLightingElement(*element())) { if (newStyle->lightingColor() != oldStyle->svgStyle()->lightingColor()) toRenderSVGResourceFilter(filter)->primitiveAttributeChanged(this, SVGNames::lighting_colorAttr); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilterPrimitive.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilterPrimitive.h index 704df3d4075..b2a293d68fe 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilterPrimitive.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilterPrimitive.h @@ -38,10 +38,12 @@ public: { } - virtual void styleDidChange(StyleDifference, const RenderStyle*); + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE { return false; } - virtual const char* renderName() const { return "RenderSVGResourceFilterPrimitive"; } - virtual bool isSVGResourceFilterPrimitive() const { return true; } + virtual void styleDidChange(StyleDifference, const RenderStyle*) OVERRIDE; + + virtual const char* renderName() const OVERRIDE { return "RenderSVGResourceFilterPrimitive"; } + virtual bool isSVGResourceFilterPrimitive() const OVERRIDE { return true; } inline void primitiveAttributeChanged(const QualifiedName& attribute) { diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceGradient.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceGradient.cpp index 4e432a56082..6f44a65b116 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceGradient.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceGradient.cpp @@ -81,12 +81,10 @@ 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).iterator->value; + OwnPtr<GradientData>& gradientData = m_gradientMap.add(object, nullptr).storedValue->value; if (!gradientData) gradientData = adoptPtr(new GradientData); - bool isPaintingText = resourceMode & ApplyToTextMode; - // Create gradient object if (!gradientData->gradient) { buildGradient(gradientData.get()); @@ -101,36 +99,29 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle* calculateGradientTransform(gradientTransform); gradientData->userspaceTransform *= gradientTransform; - if (isPaintingText) { - // Depending on font scaling factor, we may need to rescale the gradient here since - // text painting removes the scale factor from the context. - AffineTransform additionalTextTransform; - if (shouldTransformOnTextPainting(object, additionalTextTransform)) - gradientData->userspaceTransform *= additionalTextTransform; - } - gradientData->gradient->setGradientSpaceTransform(gradientData->userspaceTransform); } if (!gradientData->gradient) return false; + const SVGRenderStyle* svgStyle = style->svgStyle(); + ASSERT(svgStyle); + + AffineTransform computedGradientSpaceTransform = computeResourceSpaceTransform(object, gradientData->userspaceTransform, svgStyle, resourceMode); + gradientData->gradient->setGradientSpaceTransform(computedGradientSpaceTransform); + // Draw gradient context->save(); - if (isPaintingText) + if (resourceMode & ApplyToTextMode) context->setTextDrawingMode(resourceMode & ApplyToFillMode ? TextModeFill : TextModeStroke); - const SVGRenderStyle* svgStyle = style->svgStyle(); - ASSERT(svgStyle); - if (resourceMode & ApplyToFillMode) { - context->setAlpha(svgStyle->fillOpacity()); + context->setAlphaAsFloat(svgStyle->fillOpacity()); context->setFillGradient(gradientData->gradient); context->setFillRule(svgStyle->fillRule()); } else if (resourceMode & ApplyToStrokeMode) { - if (svgStyle->vectorEffect() == VE_NON_SCALING_STROKE) - gradientData->gradient->setGradientSpaceTransform(transformOnNonScalingStroke(object, gradientData->userspaceTransform)); - context->setAlpha(svgStyle->strokeOpacity()); + context->setAlphaAsFloat(svgStyle->strokeOpacity()); context->setStrokeGradient(gradientData->gradient); SVGRenderSupport::applyStrokeStyleToContext(context, style, object); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceLinearGradient.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceLinearGradient.h index ba1c3d27884..b829e403004 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceLinearGradient.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceLinearGradient.h @@ -33,15 +33,15 @@ public: explicit RenderSVGResourceLinearGradient(SVGLinearGradientElement*); virtual ~RenderSVGResourceLinearGradient(); - virtual const char* renderName() const { return "RenderSVGResourceLinearGradient"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGResourceLinearGradient"; } - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; } static const RenderSVGResourceType s_resourceType; - virtual SVGUnitTypes::SVGUnitType gradientUnits() const { return m_attributes.gradientUnits(); } - virtual void calculateGradientTransform(AffineTransform& transform) { transform = m_attributes.gradientTransform(); } - virtual bool collectGradientAttributes(SVGGradientElement*); - virtual void buildGradient(GradientData*) const; + virtual SVGUnitTypes::SVGUnitType gradientUnits() const OVERRIDE { return m_attributes.gradientUnits(); } + virtual void calculateGradientTransform(AffineTransform& transform) OVERRIDE { transform = m_attributes.gradientTransform(); } + virtual bool collectGradientAttributes(SVGGradientElement*) OVERRIDE; + virtual void buildGradient(GradientData*) const OVERRIDE; FloatPoint startPoint(const LinearGradientAttributes&) const; FloatPoint endPoint(const LinearGradientAttributes&) const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMarker.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMarker.cpp index d3de3b7cc64..be93b479b2d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMarker.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMarker.cpp @@ -23,7 +23,7 @@ #include "core/rendering/svg/RenderSVGResourceMarker.h" -#include "core/rendering/LayoutRectRecorder.h" +#include "core/rendering/PaintInfo.h" #include "core/rendering/svg/RenderSVGContainer.h" #include "core/rendering/svg/SVGRenderSupport.h" #include "platform/graphics/GraphicsContextStateSaver.h" @@ -49,13 +49,8 @@ void RenderSVGResourceMarker::layout() if (m_isInLayout) return; - LayoutRectRecorder recorder(*this); TemporaryChange<bool> inLayoutChange(m_isInLayout, true); - // Invalidate all resources if our layout changed. - if (everHadLayout() && selfNeedsLayout()) - removeAllClientsFromCache(); - // RenderSVGHiddenContainer overwrites layout(). We need the // layouting of RenderSVGContainer for calculating local // transformations and repaint. @@ -83,7 +78,7 @@ void RenderSVGResourceMarker::applyViewportClip(PaintInfo& paintInfo) FloatRect RenderSVGResourceMarker::markerBoundaries(const AffineTransform& markerTransformation) const { - FloatRect coordinates = RenderSVGContainer::repaintRectInLocalCoordinates(); + FloatRect coordinates = RenderSVGContainer::paintInvalidationRectInLocalCoordinates(); // Map repaint rect into parent coordinate space, in which the marker boundaries have to be evaluated coordinates = localToParentTransform().mapRect(coordinates); @@ -105,7 +100,7 @@ FloatPoint RenderSVGResourceMarker::referencePoint() const ASSERT(marker); SVGLengthContext lengthContext(marker); - return FloatPoint(marker->refXCurrentValue().value(lengthContext), marker->refYCurrentValue().value(lengthContext)); + return FloatPoint(marker->refX()->currentValue()->value(lengthContext), marker->refY()->currentValue()->value(lengthContext)); } float RenderSVGResourceMarker::angle() const @@ -114,8 +109,8 @@ float RenderSVGResourceMarker::angle() const ASSERT(marker); float angle = -1; - if (marker->orientTypeCurrentValue() == SVGMarkerOrientAngle) - angle = marker->orientAngleCurrentValue().value(); + if (marker->orientType()->currentValue()->enumValue() == SVGMarkerOrientAngle) + angle = marker->orientAngle()->currentValue()->value(); return angle; } @@ -126,7 +121,7 @@ AffineTransform RenderSVGResourceMarker::markerTransformation(const FloatPoint& ASSERT(marker); float markerAngle = angle(); - bool useStrokeWidth = marker->markerUnitsCurrentValue() == SVGMarkerUnitsStrokeWidth; + bool useStrokeWidth = marker->markerUnits()->currentValue()->enumValue() == SVGMarkerUnitsStrokeWidth; AffineTransform transform; transform.translate(origin.x(), origin.y()); @@ -142,12 +137,15 @@ void RenderSVGResourceMarker::draw(PaintInfo& paintInfo, const AffineTransform& // An empty viewBox disables rendering. SVGMarkerElement* marker = toSVGMarkerElement(element()); ASSERT(marker); - if (marker->hasAttribute(SVGNames::viewBoxAttr) && marker->viewBoxCurrentValue().isValid() && marker->viewBoxCurrentValue().isEmpty()) + if (marker->hasAttribute(SVGNames::viewBoxAttr) && marker->viewBox()->currentValue()->isValid() && marker->viewBox()->currentValue()->value().isEmpty()) return; PaintInfo info(paintInfo); - GraphicsContextStateSaver stateSaver(*info.context); - info.applyTransform(transform); + GraphicsContextStateSaver stateSaver(*info.context, false); + if (!transform.isIdentity()) { + stateSaver.save(); + info.applyTransform(transform, false); + } RenderSVGContainer::paint(info, IntPoint()); } @@ -181,8 +179,8 @@ void RenderSVGResourceMarker::calcViewport() ASSERT(marker); SVGLengthContext lengthContext(marker); - float w = marker->markerWidthCurrentValue().value(lengthContext); - float h = marker->markerHeightCurrentValue().value(lengthContext); + float w = marker->markerWidth()->currentValue()->value(lengthContext); + float h = marker->markerHeight()->currentValue()->value(lengthContext); m_viewport = FloatRect(0, 0, w, h); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMarker.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMarker.h index 625b37a652a..ba31fb21e45 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMarker.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMarker.h @@ -28,7 +28,6 @@ namespace WebCore { -class AffineTransform; class RenderObject; class RenderSVGResourceMarker FINAL : public RenderSVGResourceContainer { @@ -36,30 +35,30 @@ public: explicit RenderSVGResourceMarker(SVGMarkerElement*); virtual ~RenderSVGResourceMarker(); - virtual const char* renderName() const { return "RenderSVGResourceMarker"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGResourceMarker"; } - virtual void removeAllClientsFromCache(bool markForInvalidation = true); - virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); + virtual void removeAllClientsFromCache(bool markForInvalidation = true) OVERRIDE; + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true) OVERRIDE; void draw(PaintInfo&, const AffineTransform&); // Calculates marker boundaries, mapped to the target element's coordinate space FloatRect markerBoundaries(const AffineTransform& markerTransformation) const; - virtual void applyViewportClip(PaintInfo&); - virtual void layout(); - virtual void calcViewport(); + virtual void applyViewportClip(PaintInfo&) OVERRIDE; + virtual void layout() OVERRIDE; + virtual void calcViewport() OVERRIDE; - virtual const AffineTransform& localToParentTransform() const; + virtual const AffineTransform& localToParentTransform() const OVERRIDE; AffineTransform markerTransformation(const FloatPoint& origin, float angle, float strokeWidth) const; - virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short) { return false; } + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short) OVERRIDE { return false; } FloatPoint referencePoint() const; float angle() const; - SVGMarkerUnitsType markerUnits() const { return toSVGMarkerElement(element())->markerUnitsCurrentValue(); } + SVGMarkerUnitsType markerUnits() const { return toSVGMarkerElement(element())->markerUnits()->currentValue()->enumValue(); } - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; } static const RenderSVGResourceType s_resourceType; private: diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMasker.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMasker.cpp index 43c64ca081d..98a6d4c7639 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMasker.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMasker.cpp @@ -66,8 +66,8 @@ bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, clearInvalidationMask(); - FloatRect repaintRect = object->repaintRectInLocalCoordinates(); - if (repaintRect.isEmpty() || !element()->hasChildNodes()) + FloatRect repaintRect = object->paintInvalidationRectInLocalCoordinates(); + if (repaintRect.isEmpty() || !element()->hasChildren()) return false; // Content layer start. @@ -85,7 +85,7 @@ void RenderSVGResourceMasker::postApplyResource(RenderObject* object, GraphicsCo ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode); ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout()); - FloatRect repaintRect = object->repaintRectInLocalCoordinates(); + FloatRect repaintRect = object->paintInvalidationRectInLocalCoordinates(); const SVGRenderStyle* svgStyle = style()->svgStyle(); ASSERT(svgStyle); @@ -115,7 +115,7 @@ void RenderSVGResourceMasker::drawMaskForRenderer(GraphicsContext* context, cons ASSERT(context); AffineTransform contentTransformation; - SVGUnitTypes::SVGUnitType contentUnits = toSVGMaskElement(element())->maskContentUnitsCurrentValue(); + SVGUnitTypes::SVGUnitType contentUnits = toSVGMaskElement(element())->maskContentUnits()->currentValue()->enumValue(); if (contentUnits == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y()); contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height()); @@ -133,10 +133,13 @@ PassRefPtr<DisplayList> RenderSVGResourceMasker::asDisplayList(GraphicsContext* { ASSERT(context); - context->beginRecording(repaintRectInLocalCoordinates()); - for (Node* childNode = element()->firstChild(); childNode; childNode = childNode->nextSibling()) { - RenderObject* renderer = childNode->renderer(); - if (!childNode->isSVGElement() || !renderer) + // Using strokeBoundingBox (instead of paintInvalidationRectInLocalCoordinates) to avoid the intersection + // with local clips/mask, which may yield incorrect results when mixing objectBoundingBox and + // userSpaceOnUse units (http://crbug.com/294900). + context->beginRecording(strokeBoundingBox()); + for (Element* childElement = ElementTraversal::firstWithin(*element()); childElement; childElement = ElementTraversal::nextSibling(*childElement)) { + RenderObject* renderer = childElement->renderer(); + if (!childElement->isSVGElement() || !renderer) continue; RenderStyle* style = renderer->style(); if (!style || style->display() == NONE || style->visibility() != VISIBLE) @@ -150,24 +153,24 @@ PassRefPtr<DisplayList> RenderSVGResourceMasker::asDisplayList(GraphicsContext* void RenderSVGResourceMasker::calculateMaskContentRepaintRect() { - for (Node* childNode = element()->firstChild(); childNode; childNode = childNode->nextSibling()) { - RenderObject* renderer = childNode->renderer(); - if (!childNode->isSVGElement() || !renderer) + for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) { + RenderObject* renderer = childElement->renderer(); + if (!renderer) continue; RenderStyle* style = renderer->style(); if (!style || style->display() == NONE || style->visibility() != VISIBLE) continue; - m_maskContentBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates())); + m_maskContentBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->paintInvalidationRectInLocalCoordinates())); } } -FloatRect RenderSVGResourceMasker::resourceBoundingBox(RenderObject* object) +FloatRect RenderSVGResourceMasker::resourceBoundingBox(const RenderObject* object) { SVGMaskElement* maskElement = toSVGMaskElement(element()); ASSERT(maskElement); FloatRect objectBoundingBox = object->objectBoundingBox(); - FloatRect maskBoundaries = SVGLengthContext::resolveRectangle<SVGMaskElement>(maskElement, maskElement->maskUnitsCurrentValue(), objectBoundingBox); + FloatRect maskBoundaries = SVGLengthContext::resolveRectangle<SVGMaskElement>(maskElement, maskElement->maskUnits()->currentValue()->enumValue(), objectBoundingBox); // Resource was not layouted yet. Give back clipping rect of the mask. if (selfNeedsLayout()) @@ -177,7 +180,7 @@ FloatRect RenderSVGResourceMasker::resourceBoundingBox(RenderObject* object) calculateMaskContentRepaintRect(); FloatRect maskRect = m_maskContentBoundaries; - if (maskElement->maskContentUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + if (maskElement->maskContentUnits()->currentValue()->value() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { AffineTransform transform; transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMasker.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMasker.h index 2af52752127..e05fc0d9b95 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMasker.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMasker.h @@ -25,7 +25,6 @@ #include "core/svg/SVGUnitTypes.h" #include "platform/geometry/FloatRect.h" #include "platform/geometry/IntSize.h" -#include "platform/graphics/GraphicsContext.h" #include "platform/graphics/ImageBuffer.h" #include "wtf/HashMap.h" @@ -34,24 +33,25 @@ namespace WebCore { class DisplayList; +class GraphicsContext; class RenderSVGResourceMasker FINAL : public RenderSVGResourceContainer { public: explicit RenderSVGResourceMasker(SVGMaskElement*); virtual ~RenderSVGResourceMasker(); - virtual const char* renderName() const { return "RenderSVGResourceMasker"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGResourceMasker"; } - virtual void removeAllClientsFromCache(bool markForInvalidation = true); - virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); + virtual void removeAllClientsFromCache(bool markForInvalidation = true) OVERRIDE; + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true) OVERRIDE; virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode) OVERRIDE; virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short, const Path*, const RenderSVGShape*) OVERRIDE; - FloatRect resourceBoundingBox(RenderObject*); + FloatRect resourceBoundingBox(const RenderObject*); - SVGUnitTypes::SVGUnitType maskUnits() const { return toSVGMaskElement(element())->maskUnitsCurrentValue(); } - SVGUnitTypes::SVGUnitType maskContentUnits() const { return toSVGMaskElement(element())->maskContentUnitsCurrentValue(); } + SVGUnitTypes::SVGUnitType maskUnits() const { return toSVGMaskElement(element())->maskUnits()->currentValue()->enumValue(); } + SVGUnitTypes::SVGUnitType maskContentUnits() const { return toSVGMaskElement(element())->maskContentUnits()->currentValue()->enumValue(); } - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; } static const RenderSVGResourceType s_resourceType; private: diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourcePattern.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourcePattern.cpp index c107a793f4a..401a29057a8 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourcePattern.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourcePattern.cpp @@ -53,6 +53,7 @@ void RenderSVGResourcePattern::removeClientFromCache(RenderObject* client, bool PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsigned short resourceMode) { + ASSERT(object); PatternData* currentData = m_patternMap.get(object); if (currentData && currentData->pattern) return currentData; @@ -84,19 +85,18 @@ PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsign return 0; AffineTransform absoluteTransformIgnoringRotation; - SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransformIgnoringRotation); + SVGRenderingContext::calculateDeviceSpaceTransformation(object, absoluteTransformIgnoringRotation); // Ignore 2D rotation, as it doesn't affect the size of the tile. SVGRenderingContext::clear2DRotation(absoluteTransformIgnoringRotation); FloatRect absoluteTileBoundaries = absoluteTransformIgnoringRotation.mapRect(tileBoundaries); - FloatRect clampedAbsoluteTileBoundaries; // Scale the tile size to match the scale level of the patternTransform. absoluteTileBoundaries.scale(static_cast<float>(m_attributes.patternTransform().xScale()), static_cast<float>(m_attributes.patternTransform().yScale())); // Build tile image. - OwnPtr<ImageBuffer> tileImage = createTileImage(m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform, clampedAbsoluteTileBoundaries); + OwnPtr<ImageBuffer> tileImage = createTileImage(m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform); if (!tileImage) return 0; @@ -117,18 +117,10 @@ PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsign if (!patternTransform.isIdentity()) patternData->transform = patternTransform * patternData->transform; - // Account for text drawing resetting the context to non-scaled, see SVGInlineTextBox::paintTextWithShadows. - if (resourceMode & ApplyToTextMode) { - AffineTransform additionalTextTransformation; - if (shouldTransformOnTextPainting(object, additionalTextTransformation)) - patternData->transform *= additionalTextTransformation; - } - patternData->pattern->setPatternSpaceTransform(patternData->transform); - // Various calls above may trigger invalidations in some fringe cases (ImageBuffer allocation // failures in the SVG image cache for example). To avoid having our PatternData deleted by // removeAllClientsFromCache(), we only make it visible in the cache at the very end. - return m_patternMap.set(object, patternData.release()).iterator->value.get(); + return m_patternMap.set(object, patternData.release()).storedValue->value.get(); } bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle* style, GraphicsContext*& context, unsigned short resourceMode) @@ -150,20 +142,21 @@ bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle* if (!patternData) return false; - // Draw pattern - context->save(); - const SVGRenderStyle* svgStyle = style->svgStyle(); ASSERT(svgStyle); + AffineTransform computedPatternSpaceTransform = computeResourceSpaceTransform(object, patternData->transform, svgStyle, resourceMode); + patternData->pattern->setPatternSpaceTransform(computedPatternSpaceTransform); + + // Draw pattern + context->save(); + if (resourceMode & ApplyToFillMode) { - context->setAlpha(svgStyle->fillOpacity()); + context->setAlphaAsFloat(svgStyle->fillOpacity()); context->setFillPattern(patternData->pattern); context->setFillRule(svgStyle->fillRule()); } else if (resourceMode & ApplyToStrokeMode) { - if (svgStyle->vectorEffect() == VE_NON_SCALING_STROKE) - patternData->pattern->setPatternSpaceTransform(transformOnNonScalingStroke(object, patternData->transform)); - context->setAlpha(svgStyle->strokeOpacity()); + context->setAlphaAsFloat(svgStyle->strokeOpacity()); context->setStrokePattern(patternData->pattern); SVGRenderSupport::applyStrokeStyleToContext(context, style, object); } @@ -235,10 +228,9 @@ bool RenderSVGResourcePattern::buildTileImageTransform(RenderObject* renderer, PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const PatternAttributes& attributes, const FloatRect& tileBoundaries, const FloatRect& absoluteTileBoundaries, - const AffineTransform& tileImageTransform, - FloatRect& clampedAbsoluteTileBoundaries) const + const AffineTransform& tileImageTransform) const { - clampedAbsoluteTileBoundaries = SVGRenderingContext::clampedAbsoluteTargetRect(absoluteTileBoundaries); + FloatRect clampedAbsoluteTileBoundaries = SVGRenderingContext::clampedAbsoluteTargetRect(absoluteTileBoundaries); IntSize imageSize(roundedIntSize(clampedAbsoluteTileBoundaries.size())); if (imageSize.isEmpty()) @@ -250,11 +242,12 @@ PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const PatternA GraphicsContext* tileImageContext = tileImage->context(); ASSERT(tileImageContext); IntSize unclampedImageSize(roundedIntSize(absoluteTileBoundaries.size())); - tileImageContext->scale(FloatSize(unclampedImageSize.width() / absoluteTileBoundaries.width(), unclampedImageSize.height() / absoluteTileBoundaries.height())); + tileImageContext->scale(unclampedImageSize.width() / absoluteTileBoundaries.width(), unclampedImageSize.height() / absoluteTileBoundaries.height()); // The image buffer represents the final rendered size, so the content has to be scaled (to avoid pixelation). - tileImageContext->scale(FloatSize(clampedAbsoluteTileBoundaries.width() / tileBoundaries.width(), - clampedAbsoluteTileBoundaries.height() / tileBoundaries.height())); + tileImageContext->scale( + clampedAbsoluteTileBoundaries.width() / tileBoundaries.width(), + clampedAbsoluteTileBoundaries.height() / tileBoundaries.height()); // Apply tile image transformations. if (!tileImageTransform.isIdentity()) @@ -265,12 +258,12 @@ PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const PatternA contentTransformation = tileImageTransform; // Draw the content into the ImageBuffer. - for (Node* node = attributes.patternContentElement()->firstChild(); node; node = node->nextSibling()) { - if (!node->isSVGElement() || !node->renderer()) + for (Element* element = ElementTraversal::firstWithin(*attributes.patternContentElement()); element; element = ElementTraversal::nextSibling(*element)) { + if (!element->isSVGElement() || !element->renderer()) continue; - if (node->renderer()->needsLayout()) + if (element->renderer()->needsLayout()) return nullptr; - SVGRenderingContext::renderSubtree(tileImage->context(), node->renderer(), contentTransformation); + SVGRenderingContext::renderSubtree(tileImage->context(), element->renderer(), contentTransformation); } return tileImage.release(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourcePattern.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourcePattern.h index 56a8318e06d..d6b4f12e577 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourcePattern.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourcePattern.h @@ -46,23 +46,22 @@ class RenderSVGResourcePattern FINAL : public RenderSVGResourceContainer { public: explicit RenderSVGResourcePattern(SVGPatternElement*); - virtual const char* renderName() const { return "RenderSVGResourcePattern"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGResourcePattern"; } - virtual void removeAllClientsFromCache(bool markForInvalidation = true); - virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); + virtual void removeAllClientsFromCache(bool markForInvalidation = true) OVERRIDE; + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true) OVERRIDE; - virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); - virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*); + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode) OVERRIDE; + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*) OVERRIDE; - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; } static const RenderSVGResourceType s_resourceType; private: bool buildTileImageTransform(RenderObject*, const PatternAttributes&, const SVGPatternElement*, FloatRect& patternBoundaries, AffineTransform& tileImageTransform) const; PassOwnPtr<ImageBuffer> createTileImage(const PatternAttributes&, const FloatRect& tileBoundaries, - const FloatRect& absoluteTileBoundaries, const AffineTransform& tileImageTransform, - FloatRect& clampedAbsoluteTileBoundaries) const; + const FloatRect& absoluteTileBoundaries, const AffineTransform& tileImageTransform) const; PatternData* buildPattern(RenderObject*, unsigned short resourceMode); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceRadialGradient.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceRadialGradient.h index 43ee07601e0..1f9145a02bd 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceRadialGradient.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceRadialGradient.h @@ -33,15 +33,15 @@ public: explicit RenderSVGResourceRadialGradient(SVGRadialGradientElement*); virtual ~RenderSVGResourceRadialGradient(); - virtual const char* renderName() const { return "RenderSVGResourceRadialGradient"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGResourceRadialGradient"; } - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; } static const RenderSVGResourceType s_resourceType; - virtual SVGUnitTypes::SVGUnitType gradientUnits() const { return m_attributes.gradientUnits(); } - virtual void calculateGradientTransform(AffineTransform& transform) { transform = m_attributes.gradientTransform(); } - virtual bool collectGradientAttributes(SVGGradientElement*); - virtual void buildGradient(GradientData*) const; + virtual SVGUnitTypes::SVGUnitType gradientUnits() const OVERRIDE { return m_attributes.gradientUnits(); } + virtual void calculateGradientTransform(AffineTransform& transform) OVERRIDE { transform = m_attributes.gradientTransform(); } + virtual bool collectGradientAttributes(SVGGradientElement*) OVERRIDE; + virtual void buildGradient(GradientData*) const OVERRIDE; FloatPoint centerPoint(const RadialGradientAttributes&) const; FloatPoint focalPoint(const RadialGradientAttributes&) const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceSolidColor.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceSolidColor.cpp index a79ad3ad916..fac2a846c9a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceSolidColor.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceSolidColor.cpp @@ -21,8 +21,8 @@ #include "core/rendering/svg/RenderSVGResourceSolidColor.h" -#include "core/frame/Frame.h" #include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/rendering/style/RenderStyle.h" #include "core/rendering/svg/RenderSVGShape.h" #include "core/rendering/svg/SVGRenderSupport.h" @@ -56,9 +56,9 @@ bool RenderSVGResourceSolidColor::applyResource(RenderObject* object, RenderStyl if (resourceMode & ApplyToFillMode) { if (!isRenderingMask && svgStyle) - context->setAlpha(svgStyle->fillOpacity()); + context->setAlphaAsFloat(svgStyle->fillOpacity()); else - context->setAlpha(1); + context->setAlphaAsFloat(1); context->setFillColor(m_color); if (!isRenderingMask) context->setFillRule(svgStyle ? svgStyle->fillRule() : RULE_NONZERO); @@ -68,7 +68,7 @@ bool RenderSVGResourceSolidColor::applyResource(RenderObject* object, RenderStyl } else if (resourceMode & ApplyToStrokeMode) { // When rendering the mask for a RenderSVGResourceClipper, the stroke code path is never hit. ASSERT(!isRenderingMask); - context->setAlpha(svgStyle ? svgStyle->strokeOpacity() : 1); + context->setAlphaAsFloat(svgStyle ? svgStyle->strokeOpacity() : 1); context->setStrokeColor(m_color); if (style) diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceSolidColor.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceSolidColor.h index 85937ce9ef1..3583a0d1aec 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceSolidColor.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceSolidColor.h @@ -26,18 +26,18 @@ namespace WebCore { -class RenderSVGResourceSolidColor : public RenderSVGResource { +class RenderSVGResourceSolidColor FINAL : public RenderSVGResource { public: RenderSVGResourceSolidColor(); virtual ~RenderSVGResourceSolidColor(); - virtual void removeAllClientsFromCache(bool = true) { } - virtual void removeClientFromCache(RenderObject*, bool = true) { } + virtual void removeAllClientsFromCache(bool = true) OVERRIDE { } + virtual void removeClientFromCache(RenderObject*, bool = true) OVERRIDE { } - virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); - virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*); + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode) OVERRIDE; + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*) OVERRIDE; - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; } static const RenderSVGResourceType s_resourceType; const Color& color() const { return m_color; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRoot.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRoot.cpp index a4355cd4d9a..d88947d3574 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRoot.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRoot.cpp @@ -25,19 +25,21 @@ #include "core/rendering/svg/RenderSVGRoot.h" -#include "core/frame/Frame.h" +#include "core/frame/LocalFrame.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/LayoutRepainter.h" +#include "core/rendering/RenderLayer.h" #include "core/rendering/RenderPart.h" #include "core/rendering/RenderView.h" #include "core/rendering/svg/RenderSVGResourceContainer.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGRenderingContext.h" #include "core/rendering/svg/SVGResources.h" #include "core/rendering/svg/SVGResourcesCache.h" #include "core/svg/SVGElement.h" #include "core/svg/SVGSVGElement.h" #include "core/svg/graphics/SVGImage.h" +#include "platform/LengthFunctions.h" #include "platform/graphics/GraphicsContext.h" using namespace std; @@ -49,6 +51,7 @@ RenderSVGRoot::RenderSVGRoot(SVGElement* node) , m_objectBoundingBoxValid(false) , m_isLayoutSizeChanged(false) , m_needsBoundariesOrTransformUpdate(true) + , m_hasBoxDecorations(false) { } @@ -56,19 +59,13 @@ RenderSVGRoot::~RenderSVGRoot() { } -void RenderSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const +void RenderSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const { // Spec: http://www.w3.org/TR/SVG/coords.html#IntrinsicSizing // SVG needs to specify how to calculate some intrinsic sizing properties to enable inclusion within other languages. // The intrinsic width and height of the viewport of SVG content must be determined from the ‘width’ and ‘height’ attributes. - // If either of these are not specified, a value of '100%' must be assumed. Note: the ‘width’ and ‘height’ attributes are not - // the same as the CSS width and height properties. Specifically, percentage values do not provide an intrinsic width or height, - // and do not indicate a percentage of the containing block. Rather, once the viewport is established, they indicate the portion - // of the viewport that is actually covered by image data. SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); - Length intrinsicWidthAttribute = svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties); - Length intrinsicHeightAttribute = svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties); // The intrinsic aspect ratio of the viewport of SVG content is necessary for example, when including SVG from an ‘object’ // element in HTML styled with CSS. It is possible (indeed, common) for an SVG graphic to have an intrinsic aspect ratio but @@ -77,33 +74,21 @@ void RenderSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, d // - If the ‘width’ and ‘height’ of the rootmost ‘svg’ element are both specified with unit identifiers (in, mm, cm, pt, pc, // px, em, ex) or in user units, then the aspect ratio is calculated from the ‘width’ and ‘height’ attributes after // resolving both values to user units. - if (intrinsicWidthAttribute.isFixed() || intrinsicHeightAttribute.isFixed()) { - if (intrinsicWidthAttribute.isFixed()) - intrinsicSize.setWidth(floatValueForLength(intrinsicWidthAttribute, 0, 0)); - if (intrinsicHeightAttribute.isFixed()) - intrinsicSize.setHeight(floatValueForLength(intrinsicHeightAttribute, 0, 0)); - if (!intrinsicSize.isEmpty()) - intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); - return; - } + intrinsicSize.setWidth(floatValueForLength(svg->intrinsicWidth(), 0)); + intrinsicSize.setHeight(floatValueForLength(svg->intrinsicHeight(), 0)); - // - If either/both of the ‘width’ and ‘height’ of the rootmost ‘svg’ element are in percentage units (or omitted), the - // aspect ratio is calculated from the width and height values of the ‘viewBox’ specified for the current SVG document - // fragment. If the ‘viewBox’ is not correctly specified, or set to 'none', the intrinsic aspect ratio cannot be - // calculated and is considered unspecified. - intrinsicSize = svg->viewBoxCurrentValue().size(); if (!intrinsicSize.isEmpty()) { - // The viewBox can only yield an intrinsic ratio, not an intrinsic size. intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); - intrinsicSize = FloatSize(); - return; - } - - // If our intrinsic size is in percentage units, return those to the caller through the intrinsicSize. Notify the caller - // about the special situation, by setting isPercentageIntrinsicSize=true, so it knows how to interpret the return values. - if (intrinsicWidthAttribute.isPercent() && intrinsicHeightAttribute.isPercent()) { - isPercentageIntrinsicSize = true; - intrinsicSize = FloatSize(intrinsicWidthAttribute.percent(), intrinsicHeightAttribute.percent()); + } else { + // - If either/both of the ‘width’ and ‘height’ of the rootmost ‘svg’ element are in percentage units (or omitted), the + // aspect ratio is calculated from the width and height values of the ‘viewBox’ specified for the current SVG document + // fragment. If the ‘viewBox’ is not correctly specified, or set to 'none', the intrinsic aspect ratio cannot be + // calculated and is considered unspecified. + FloatSize viewBoxSize = svg->viewBox()->currentValue()->value().size(); + if (!viewBoxSize.isEmpty()) { + // The viewBox can only yield an intrinsic ratio, not an intrinsic size. + intrinsicRatio = viewBoxSize.width() / static_cast<double>(viewBoxSize.height()); + } } } @@ -117,20 +102,20 @@ bool RenderSVGRoot::isEmbeddedThroughFrameContainingSVGDocument() const if (!node()) return false; - Frame* frame = node()->document().frame(); + LocalFrame* frame = node()->document().frame(); if (!frame) return false; // If our frame has an owner renderer, we're embedded through eg. object/embed/iframe, - // but we only negotiate if we're in an SVG document. - if (!frame->ownerRenderer()) + // but we only negotiate if we're in an SVG document inside a embedded object (object/embed). + if (!frame->ownerRenderer() || !frame->ownerRenderer()->isEmbeddedObject()) return false; return frame->document()->isSVGDocument(); } -static inline LayoutUnit resolveLengthAttributeForSVG(const Length& length, float scale, float maxSize, RenderView* renderView) +static inline LayoutUnit resolveLengthAttributeForSVG(const Length& length, float scale, float maxSize) { - return static_cast<LayoutUnit>(valueForLength(length, maxSize, renderView) * (length.isFixed() ? scale : 1)); + return static_cast<LayoutUnit>(valueForLength(length, maxSize) * (length.isFixed() ? scale : 1)); } LayoutUnit RenderSVGRoot::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const @@ -142,15 +127,14 @@ LayoutUnit RenderSVGRoot::computeReplacedLogicalWidth(ShouldComputePreferred sho if (!m_containerSize.isEmpty()) return m_containerSize.width(); + if (isEmbeddedThroughFrameContainingSVGDocument()) + return containingBlock()->availableLogicalWidth(); + if (style()->logicalWidth().isSpecified() || style()->logicalMaxWidth().isSpecified()) return RenderReplaced::computeReplacedLogicalWidth(shouldComputePreferred); - if (svg->widthAttributeEstablishesViewport()) - return resolveLengthAttributeForSVG(svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties), style()->effectiveZoom(), containingBlock()->availableLogicalWidth(), view()); - - // SVG embedded through object/embed/iframe. - if (isEmbeddedThroughFrameContainingSVGDocument()) - return document().frame()->ownerRenderer()->availableLogicalWidth(); + if (svg->hasIntrinsicWidth()) + return resolveLengthAttributeForSVG(svg->intrinsicWidth(), style()->effectiveZoom(), containingBlock()->availableLogicalWidth().toFloat()); // SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG. return RenderReplaced::computeReplacedLogicalWidth(shouldComputePreferred); @@ -165,27 +149,14 @@ LayoutUnit RenderSVGRoot::computeReplacedLogicalHeight() const if (!m_containerSize.isEmpty()) return m_containerSize.height(); + if (isEmbeddedThroughFrameContainingSVGDocument()) + return containingBlock()->availableLogicalHeight(IncludeMarginBorderPadding); + if (style()->logicalHeight().isSpecified() || style()->logicalMaxHeight().isSpecified()) return RenderReplaced::computeReplacedLogicalHeight(); - if (svg->heightAttributeEstablishesViewport()) { - Length height = svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties); - if (height.isPercent()) { - RenderBlock* cb = containingBlock(); - ASSERT(cb); - while (cb->isAnonymous()) { - cb = cb->containingBlock(); - cb->addPercentHeightDescendant(const_cast<RenderSVGRoot*>(this)); - } - } else - RenderBlock::removePercentHeightDescendant(const_cast<RenderSVGRoot*>(this)); - - return resolveLengthAttributeForSVG(height, style()->effectiveZoom(), containingBlock()->availableLogicalHeight(IncludeMarginBorderPadding), view()); - } - - // SVG embedded through object/embed/iframe. - if (isEmbeddedThroughFrameContainingSVGDocument()) - return document().frame()->ownerRenderer()->availableLogicalHeight(IncludeMarginBorderPadding); + if (svg->hasIntrinsicHeight()) + return resolveLengthAttributeForSVG(svg->intrinsicHeight(), style()->effectiveZoom(), containingBlock()->availableLogicalHeight(IncludeMarginBorderPadding).toFloat()); // SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG. return RenderReplaced::computeReplacedLogicalHeight(); @@ -195,13 +166,11 @@ void RenderSVGRoot::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); - // Arbitrary affine transforms are incompatible with LayoutState. - LayoutStateDisabler layoutStateDisabler(view()); + ForceHorriblySlowRectMapping slowRectMapping(*this); bool needsLayout = selfNeedsLayout(); - LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && needsLayout); + LayoutRepainter repainter(*this, checkForPaintInvalidationDuringLayout() && needsLayout); LayoutSize oldSize = size(); updateLogicalWidth(); @@ -222,13 +191,34 @@ void RenderSVGRoot::layout() m_needsBoundariesOrTransformUpdate = false; } - updateLayerTransform(); + m_overflow.clear(); + addVisualEffectOverflow(); - repainter.repaintAfterLayout(); + if (!shouldApplyViewportClip()) { + FloatRect contentRepaintRect = paintInvalidationRectInLocalCoordinates(); + contentRepaintRect = m_localToBorderBoxTransform.mapRect(contentRepaintRect); + addVisualOverflow(enclosingLayoutRect(contentRepaintRect)); + } + updateLayerTransformAfterLayout(); + m_hasBoxDecorations = isDocumentElement() ? calculateHasBoxDecorations() : hasBoxDecorations(); + invalidateBackgroundObscurationStatus(); + + repainter.repaintAfterLayout(); clearNeedsLayout(); } +bool RenderSVGRoot::shouldApplyViewportClip() const +{ + // the outermost svg is clipped if auto, and svg document roots are always clipped + // When the svg is stand-alone (isDocumentElement() == true) the viewport clipping should always + // be applied, noting that the window scrollbars should be hidden if overflow=hidden. + return style()->overflowX() == OHIDDEN + || style()->overflowX() == OAUTO + || style()->overflowX() == OSCROLL + || this->isDocumentElement(); +} + void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // An empty viewport disables rendering. @@ -239,6 +229,10 @@ void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paint if (paintInfo.context->paintingDisabled()) return; + // SVG outlines are painted during PaintPhaseForeground. + if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) + return; + // An empty viewBox also disables rendering. // (http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute) SVGSVGElement* svg = toSVGSVGElement(node()); @@ -257,8 +251,9 @@ void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paint PaintInfo childPaintInfo(paintInfo); childPaintInfo.context->save(); - // Apply initial viewport clip - not affected by overflow handling - childPaintInfo.context->clip(pixelSnappedIntRect(overflowClipRect(paintOffset, paintInfo.renderRegion))); + // Apply initial viewport clip + if (shouldApplyViewportClip()) + childPaintInfo.context->clip(pixelSnappedIntRect(overflowClipRect(paintOffset))); // Convert from container offsets (html renderers) to a relative transform (svg renderers). // Transform from our paint container's coordinate system to our local coords. @@ -292,13 +287,22 @@ void RenderSVGRoot::willBeDestroyed() void RenderSVGRoot::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - if (diff == StyleDifferenceLayout) + if (diff.needsFullLayout()) setNeedsBoundariesUpdate(); + if (diff.needsRepaint()) { + // Box decorations may have appeared/disappeared - recompute status. + m_hasBoxDecorations = calculateHasBoxDecorations(); + } RenderReplaced::styleDidChange(diff, oldStyle); SVGResourcesCache::clientStyleChanged(this, diff, style()); } +bool RenderSVGRoot::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + return child->isSVG() && !(child->isSVGInline() || child->isSVGInlineText()); +} + void RenderSVGRoot::addChild(RenderObject* child, RenderObject* beforeChild) { RenderReplaced::addChild(child, beforeChild); @@ -330,12 +334,13 @@ void RenderSVGRoot::buildLocalToBorderBoxTransform() SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); float scale = style()->effectiveZoom(); - SVGPoint translate = svg->currentTranslate(); + FloatPoint translate = svg->currentTranslate(); LayoutSize borderAndPadding(borderLeft() + paddingLeft(), borderTop() + paddingTop()); m_localToBorderBoxTransform = svg->viewBoxToViewTransform(contentWidth() / scale, contentHeight() / scale); - if (borderAndPadding.isEmpty() && scale == 1 && translate == SVGPoint::zero()) + AffineTransform viewToBorderBoxTransform(scale, 0, 0, scale, borderAndPadding.width() + translate.x(), borderAndPadding.height() + translate.y()); + if (viewToBorderBoxTransform.isIdentity()) return; - m_localToBorderBoxTransform = AffineTransform(scale, 0, 0, scale, borderAndPadding.width() + translate.x(), borderAndPadding.height() + translate.y()) * m_localToBorderBoxTransform; + m_localToBorderBoxTransform = viewToBorderBoxTransform * m_localToBorderBoxTransform; } const AffineTransform& RenderSVGRoot::localToParentTransform() const @@ -349,23 +354,53 @@ const AffineTransform& RenderSVGRoot::localToParentTransform() const return m_localToParentTransform; } -LayoutRect RenderSVGRoot::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const +LayoutRect RenderSVGRoot::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const { - return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer); + // This is an open-coded aggregate of SVGRenderSupport::clippedOverflowRectForPaintInvalidation, + // RenderSVGRoot::computeFloatRectForPaintInvalidation and RenderReplaced::clippedOverflowRectForPaintInvalidation. + // The reason for this is to optimize/minimize the repaint rect when the box is not "decorated" + // (does not have background/border/etc.) + + // Return early for any cases where we don't actually paint. + if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) + return LayoutRect(); + + // Compute the repaint rect of the content of the SVG in the border-box coordinate space. + FloatRect contentRepaintRect = paintInvalidationRectInLocalCoordinates(); + contentRepaintRect = m_localToBorderBoxTransform.mapRect(contentRepaintRect); + + // Apply initial viewport clip, overflow:visible content is added to visualOverflow + // but the most common case is that overflow is hidden, so always intersect. + contentRepaintRect.intersect(pixelSnappedBorderBoxRect()); + + LayoutRect repaintRect = enclosingLayoutRect(contentRepaintRect); + // If the box is decorated or is overflowing, extend it to include the border-box and overflow. + if (m_hasBoxDecorations || hasRenderOverflow()) { + // The selectionRect can project outside of the overflowRect, so take their union + // for repainting to avoid selection painting glitches. + LayoutRect decoratedRepaintRect = unionRect(localSelectionRect(false), visualOverflowRect()); + repaintRect.unite(decoratedRepaintRect); + } + + // Compute the repaint rect in the parent coordinate space. + LayoutRect rect = enclosingIntRect(repaintRect); + RenderReplaced::mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect); + return rect; } -void RenderSVGRoot::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const +void RenderSVGRoot::computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect& paintInvalidationRect, bool fixed) const { // Apply our local transforms (except for x/y translation), then our shadow, // and then call RenderBox's method to handle all the normal CSS Box model bits - repaintRect = m_localToBorderBoxTransform.mapRect(repaintRect); + paintInvalidationRect = m_localToBorderBoxTransform.mapRect(paintInvalidationRect); - // Apply initial viewport clip - not affected by overflow settings - repaintRect.intersect(pixelSnappedBorderBoxRect()); + // Apply initial viewport clip + if (shouldApplyViewportClip()) + paintInvalidationRect.intersect(pixelSnappedBorderBoxRect()); - LayoutRect rect = enclosingIntRect(repaintRect); - RenderReplaced::computeRectForRepaint(repaintContainer, rect, fixed); - repaintRect = rect; + LayoutRect rect = enclosingIntRect(paintInvalidationRect); + RenderReplaced::mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, fixed); + paintInvalidationRect = rect; } // This method expects local CSS box coordinates. @@ -374,7 +409,9 @@ void RenderSVGRoot::computeFloatRectForRepaint(const RenderLayerModelObject* rep void RenderSVGRoot::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const { ASSERT(mode & ~IsFixed); // We should have no fixed content in the SVG rendering tree. - ASSERT(mode & UseTransforms); // mapping a point through SVG w/o respecting trasnforms is useless. + // We used to have this ASSERT here, but we removed it when enabling layer squashing. + // See http://crbug.com/364901 + // ASSERT(mode & UseTransforms); // mapping a point through SVG w/o respecting trasnforms is useless. RenderReplaced::mapLocalToContainer(repaintContainer, transformState, mode | ApplyContainerFlip, wasFixed); } @@ -388,7 +425,6 @@ void RenderSVGRoot::updateCachedBoundaries() { SVGRenderSupport::computeContainerBoundingBoxes(this, m_objectBoundingBox, m_objectBoundingBoxValid, m_strokeBoundingBox, m_repaintBoundingBox); SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox); - m_repaintBoundingBox.inflate(borderAndPaddingWidth()); } bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) @@ -412,11 +448,11 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re } // If we didn't early exit above, we've just hit the container <svg> element. Unlike SVG 1.1, 2nd Edition allows container elements to be hit. - if (hitTestAction == HitTestBlockBackground && visibleToHitTestRequest(request)) { - // Only return true here, if the last hit testing phase 'BlockBackground' is executed. If we'd return true in the 'Foreground' phase, - // hit testing would stop immediately. For SVG only trees this doesn't matter. Though when we have a <foreignObject> subtree we need - // to be able to detect hits on the background of a <div> element. If we'd return true here in the 'Foreground' phase, we are not able - // to detect these hits anymore. + if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && visibleToHitTestRequest(request)) { + // Only return true here, if the last hit testing phase 'BlockBackground' (or 'ChildBlockBackground' - depending on context) is executed. + // If we'd return true in the 'Foreground' phase, hit testing would stop immediately. For SVG only trees this doesn't matter. + // Though when we have a <foreignObject> subtree we need to be able to detect hits on the background of a <div> element. + // If we'd return true here in the 'Foreground' phase, we are not able to detect these hits anymore. LayoutRect boundsRect(accumulatedOffset + location(), size()); if (locationInContainer.intersects(boundsRect)) { updateHitTestResult(result, pointInBorderBox); @@ -428,27 +464,4 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re return false; } -bool RenderSVGRoot::hasRelativeDimensions() const -{ - SVGSVGElement* svg = toSVGSVGElement(node()); - ASSERT(svg); - - return svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties).isPercent() || svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties).isPercent(); -} - -bool RenderSVGRoot::hasRelativeIntrinsicLogicalWidth() const -{ - SVGSVGElement* svg = toSVGSVGElement(node()); - ASSERT(svg); - return svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties).isPercent(); -} - -bool RenderSVGRoot::hasRelativeLogicalHeight() const -{ - SVGSVGElement* svg = toSVGSVGElement(node()); - ASSERT(svg); - - return svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties).isPercent(); -} - } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRoot.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRoot.h index f907222eb81..b38d51cbde8 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRoot.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRoot.h @@ -24,12 +24,10 @@ #define RenderSVGRoot_h #include "core/rendering/RenderReplaced.h" -#include "core/rendering/svg/SVGRenderSupport.h" #include "platform/geometry/FloatRect.h" namespace WebCore { -class AffineTransform; class SVGElement; class RenderSVGRoot FINAL : public RenderReplaced { @@ -40,66 +38,77 @@ public: bool isEmbeddedThroughSVGImage() const; bool isEmbeddedThroughFrameContainingSVGDocument() const; - virtual void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const; + virtual void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const OVERRIDE; RenderObject* firstChild() const { ASSERT(children() == virtualChildren()); return children()->firstChild(); } RenderObject* lastChild() const { ASSERT(children() == virtualChildren()); return children()->lastChild(); } + // If you have a RenderSVGRoot, use firstChild or lastChild instead. + void slowFirstChild() const WTF_DELETED_FUNCTION; + void slowLastChild() const WTF_DELETED_FUNCTION; + const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } bool isLayoutSizeChanged() const { return m_isLayoutSizeChanged; } - virtual void setNeedsBoundariesUpdate() { m_needsBoundariesOrTransformUpdate = true; } - virtual bool needsBoundariesUpdate() OVERRIDE { return m_needsBoundariesOrTransformUpdate; } - virtual void setNeedsTransformUpdate() { m_needsBoundariesOrTransformUpdate = true; } + virtual void setNeedsBoundariesUpdate() OVERRIDE { m_needsBoundariesOrTransformUpdate = true; } + virtual void setNeedsTransformUpdate() OVERRIDE { m_needsBoundariesOrTransformUpdate = true; } IntSize containerSize() const { return m_containerSize; } - void setContainerSize(const IntSize& containerSize) { m_containerSize = containerSize; } - - virtual bool hasRelativeDimensions() const OVERRIDE; - virtual bool hasRelativeIntrinsicLogicalWidth() const OVERRIDE; - virtual bool hasRelativeLogicalHeight() const OVERRIDE; + void setContainerSize(const IntSize& containerSize) + { + // SVGImage::draw() does a view layout prior to painting, + // and we need that layout to know of the new size otherwise + // the rendering may be incorrectly using the old size. + if (m_containerSize != containerSize) + setNeedsLayoutAndFullPaintInvalidation(); + m_containerSize = containerSize; + } // localToBorderBoxTransform maps local SVG viewport coordinates to local CSS box coordinates. const AffineTransform& localToBorderBoxTransform() const { return m_localToBorderBoxTransform; } private: - virtual RenderObjectChildList* virtualChildren() { return children(); } - virtual const RenderObjectChildList* virtualChildren() const { return children(); } + virtual RenderObjectChildList* virtualChildren() OVERRIDE { return children(); } + virtual const RenderObjectChildList* virtualChildren() const OVERRIDE { return children(); } - virtual bool isSVGRoot() const { return true; } - virtual const char* renderName() const { return "RenderSVGRoot"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGRoot"; } + virtual bool isSVGRoot() const OVERRIDE { return true; } + virtual bool isSVG() const OVERRIDE { return true; } virtual LayoutUnit computeReplacedLogicalWidth(ShouldComputePreferred = ComputeActual) const OVERRIDE; - virtual LayoutUnit computeReplacedLogicalHeight() const; - virtual void layout(); - virtual void paintReplaced(PaintInfo&, const LayoutPoint&); + virtual LayoutUnit computeReplacedLogicalHeight() const OVERRIDE; + virtual void layout() OVERRIDE; + virtual void paintReplaced(PaintInfo&, const LayoutPoint&) OVERRIDE; - virtual void willBeDestroyed(); - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void willBeDestroyed() OVERRIDE; + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE; virtual void removeChild(RenderObject*) OVERRIDE; + virtual bool canHaveWhitespaceChildren() const OVERRIDE { return false; } virtual void insertedIntoTree() OVERRIDE; virtual void willBeRemovedFromTree() OVERRIDE; - virtual const AffineTransform& localToParentTransform() const; + virtual const AffineTransform& localToParentTransform() const OVERRIDE; - virtual FloatRect objectBoundingBox() const { return m_objectBoundingBox; } - virtual FloatRect strokeBoundingBox() const { return m_strokeBoundingBox; } - virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; } + virtual FloatRect objectBoundingBox() const OVERRIDE { return m_objectBoundingBox; } + virtual FloatRect strokeBoundingBox() const OVERRIDE { return m_strokeBoundingBox; } + virtual FloatRect paintInvalidationRectInLocalCoordinates() const OVERRIDE { return m_repaintBoundingBox; } virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE; - virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const OVERRIDE; + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const OVERRIDE; + virtual void computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect& paintInvalidationRect, bool fixed) const OVERRIDE; virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE; virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE; - virtual bool canBeSelectionLeaf() const { return false; } - virtual bool canHaveChildren() const { return true; } + virtual bool canBeSelectionLeaf() const OVERRIDE { return false; } + virtual bool canHaveChildren() const OVERRIDE { return true; } + bool shouldApplyViewportClip() const; void updateCachedBoundaries(); void buildLocalToBorderBoxTransform(); @@ -113,6 +122,7 @@ private: AffineTransform m_localToBorderBoxTransform; bool m_isLayoutSizeChanged : 1; bool m_needsBoundariesOrTransformUpdate : 1; + bool m_hasBoxDecorations : 1; }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderSVGRoot, isSVGRoot()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGShape.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGShape.cpp index 04298f7e49d..dfd09e70aef 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGShape.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGShape.cpp @@ -26,17 +26,16 @@ */ #include "config.h" - #include "core/rendering/svg/RenderSVGShape.h" #include "core/rendering/GraphicsContextAnnotator.h" #include "core/rendering/HitTestRequest.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/LayoutRepainter.h" #include "core/rendering/PointerEventsHitRules.h" #include "core/rendering/svg/RenderSVGResourceMarker.h" #include "core/rendering/svg/RenderSVGResourceSolidColor.h" #include "core/rendering/svg/SVGPathData.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGRenderingContext.h" #include "core/rendering/svg/SVGResources.h" #include "core/rendering/svg/SVGResourcesCache.h" @@ -63,7 +62,7 @@ void RenderSVGShape::updateShapeFromElement() { m_path.clear(); m_path = adoptPtr(new Path); - ASSERT(RenderSVGShape::isEmpty()); + ASSERT(RenderSVGShape::isShapeEmpty()); updatePathFromGraphicsElement(toSVGGraphicsElement(element()), path()); processMarkerPositions(); @@ -72,11 +71,6 @@ void RenderSVGShape::updateShapeFromElement() m_strokeBoundingBox = calculateStrokeBoundingBox(); } -bool RenderSVGShape::isEmpty() const -{ - return path().isEmpty(); -} - void RenderSVGShape::fillShape(GraphicsContext* context) const { context->fillPath(path()); @@ -119,8 +113,8 @@ bool RenderSVGShape::fillContains(const FloatPoint& point, bool requiresFill, co if (!m_fillBoundingBox.contains(point)) return false; - Color fallbackColor; - if (requiresFill && !RenderSVGResource::fillPaintingResource(this, style(), fallbackColor)) + bool hasFallback; + if (requiresFill && !RenderSVGResource::fillPaintingResource(this, style(), hasFallback)) return false; return shapeDependentFillContains(point, fillRule); @@ -131,8 +125,8 @@ bool RenderSVGShape::strokeContains(const FloatPoint& point, bool requiresStroke if (!strokeBoundingBox().contains(point)) return false; - Color fallbackColor; - if (requiresStroke && !RenderSVGResource::strokePaintingResource(this, style(), fallbackColor)) + bool hasFallback; + if (requiresStroke && !RenderSVGResource::strokePaintingResource(this, style(), hasFallback)) return false; return shapeDependentStrokeContains(point); @@ -140,7 +134,6 @@ bool RenderSVGShape::strokeContains(const FloatPoint& point, bool requiresStroke void RenderSVGShape::layout() { - LayoutRectRecorder recorder(*this); LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(this) && selfNeedsLayout()); bool updateCachedBoundariesInParents = false; @@ -201,7 +194,7 @@ bool RenderSVGShape::shouldGenerateMarkerPositions() const if (!style()->svgStyle()->hasMarkers()) return false; - if (!toSVGGraphicsElement(element())->supportsMarkers()) + if (!SVGResources::supportsMarkers(*toSVGGraphicsElement(element()))) return false; SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); @@ -213,13 +206,12 @@ bool RenderSVGShape::shouldGenerateMarkerPositions() const void RenderSVGShape::fillShape(RenderStyle* style, GraphicsContext* context) { - Color fallbackColor; - if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(this, style, fallbackColor)) { - if (fillPaintingResource->applyResource(this, style, context, ApplyToFillMode)) + bool hasFallback; + if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(this, style, hasFallback)) { + if (fillPaintingResource->applyResource(this, style, context, ApplyToFillMode)) { fillPaintingResource->postApplyResource(this, context, ApplyToFillMode, 0, this); - else if (fallbackColor.isValid()) { + } else if (hasFallback) { RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource(); - fallbackResource->setColor(fallbackColor); if (fallbackResource->applyResource(this, style, context, ApplyToFillMode)) fallbackResource->postApplyResource(this, context, ApplyToFillMode, 0, this); } @@ -228,13 +220,12 @@ void RenderSVGShape::fillShape(RenderStyle* style, GraphicsContext* context) void RenderSVGShape::strokeShape(RenderStyle* style, GraphicsContext* context) { - Color fallbackColor; - if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(this, style, fallbackColor)) { - if (strokePaintingResource->applyResource(this, style, context, ApplyToStrokeMode)) + bool hasFallback; + if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(this, style, hasFallback)) { + if (strokePaintingResource->applyResource(this, style, context, ApplyToStrokeMode)) { strokePaintingResource->postApplyResource(this, context, ApplyToStrokeMode, 0, this); - else if (fallbackColor.isValid()) { + } else if (hasFallback) { RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource(); - fallbackResource->setColor(fallbackColor); if (fallbackResource->applyResource(this, style, context, ApplyToStrokeMode)) fallbackResource->postApplyResource(this, context, ApplyToStrokeMode, 0, this); } @@ -244,68 +235,67 @@ void RenderSVGShape::strokeShape(RenderStyle* style, GraphicsContext* context) void RenderSVGShape::paint(PaintInfo& paintInfo, const LayoutPoint&) { ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this); - - if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || isEmpty()) + if (paintInfo.context->paintingDisabled() + || paintInfo.phase != PaintPhaseForeground + || style()->visibility() == HIDDEN + || isShapeEmpty()) return; - FloatRect boundingBox = repaintRectInLocalCoordinates(); + + FloatRect boundingBox = paintInvalidationRectInLocalCoordinates(); if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(boundingBox, m_localTransform, paintInfo)) return; PaintInfo childPaintInfo(paintInfo); - bool drawsOutline = style()->outlineWidth() && (childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline); - if (drawsOutline || childPaintInfo.phase == PaintPhaseForeground) { - GraphicsContextStateSaver stateSaver(*childPaintInfo.context); - childPaintInfo.applyTransform(m_localTransform); - - if (childPaintInfo.phase == PaintPhaseForeground) { - SVGRenderingContext renderingContext(this, childPaintInfo); - - if (renderingContext.isRenderingPrepared()) { - const SVGRenderStyle* svgStyle = style()->svgStyle(); - if (svgStyle->shapeRendering() == SR_CRISPEDGES) - childPaintInfo.context->setShouldAntialias(false); - - for (int i = 0; i < 3; i++) { - switch (svgStyle->paintOrderType(i)) { - case PT_FILL: - fillShape(this->style(), childPaintInfo.context); - break; - case PT_STROKE: - if (svgStyle->hasVisibleStroke()) { - GraphicsContextStateSaver stateSaver(*childPaintInfo.context, false); - AffineTransform nonScalingTransform; - - if (hasNonScalingStroke()) { - AffineTransform nonScalingTransform = nonScalingStrokeTransform(); - if (!setupNonScalingStrokeContext(nonScalingTransform, stateSaver)) - return; - } - - strokeShape(this->style(), childPaintInfo.context); - } - break; - case PT_MARKERS: - if (!m_markerPositions.isEmpty()) - drawMarkers(childPaintInfo); - break; - default: - ASSERT_NOT_REACHED(); - break; + + GraphicsContextStateSaver stateSaver(*childPaintInfo.context); + childPaintInfo.applyTransform(m_localTransform); + + SVGRenderingContext renderingContext(this, childPaintInfo); + + if (renderingContext.isRenderingPrepared()) { + const SVGRenderStyle* svgStyle = style()->svgStyle(); + if (svgStyle->shapeRendering() == SR_CRISPEDGES) + childPaintInfo.context->setShouldAntialias(false); + + for (int i = 0; i < 3; i++) { + switch (svgStyle->paintOrderType(i)) { + case PT_FILL: + fillShape(this->style(), childPaintInfo.context); + break; + case PT_STROKE: + if (svgStyle->hasVisibleStroke()) { + GraphicsContextStateSaver stateSaver(*childPaintInfo.context, false); + AffineTransform nonScalingTransform; + + if (hasNonScalingStroke()) { + AffineTransform nonScalingTransform = nonScalingStrokeTransform(); + if (!setupNonScalingStrokeContext(nonScalingTransform, stateSaver)) + return; } + + strokeShape(this->style(), childPaintInfo.context); } + break; + case PT_MARKERS: + if (!m_markerPositions.isEmpty()) + drawMarkers(childPaintInfo); + break; + default: + ASSERT_NOT_REACHED(); + break; } } - - if (drawsOutline) - paintOutline(childPaintInfo, IntRect(boundingBox)); } + + if (style()->outlineWidth()) + paintOutline(childPaintInfo, IntRect(boundingBox)); } // This method is called from inside paintOutline() since we call paintOutline() // while transformed to our coord system, return local coords void RenderSVGShape::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) { - IntRect rect = enclosingIntRect(repaintRectInLocalCoordinates()); + IntRect rect = enclosingIntRect(paintInvalidationRectInLocalCoordinates()); if (!rect.isEmpty()) rects.append(rect); } @@ -417,7 +407,7 @@ FloatRect RenderSVGShape::calculateStrokeBoundingBox() const void RenderSVGShape::updateRepaintBoundingBox() { m_repaintBoundingBox = strokeBoundingBox(); - if (strokeWidth() < 1.0f) + if (strokeWidth() < 1.0f && !m_repaintBoundingBox.isEmpty()) m_repaintBoundingBox.inflate(1); SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox); } @@ -425,13 +415,13 @@ void RenderSVGShape::updateRepaintBoundingBox() float RenderSVGShape::strokeWidth() const { SVGLengthContext lengthContext(element()); - return style()->svgStyle()->strokeWidth().value(lengthContext); + return style()->svgStyle()->strokeWidth()->value(lengthContext); } bool RenderSVGShape::hasSmoothStroke() const { const SVGRenderStyle* svgStyle = style()->svgStyle(); - return svgStyle->strokeDashArray().isEmpty() + return svgStyle->strokeDashArray()->isEmpty() && svgStyle->strokeMiterLimit() == svgStyle->initialStrokeMiterLimit() && svgStyle->joinStyle() == svgStyle->initialJoinStyle() && svgStyle->capStyle() == svgStyle->initialCapStyle(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGShape.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGShape.h index f800b2db555..12a703f063b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGShape.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGShape.h @@ -38,9 +38,6 @@ namespace WebCore { class FloatPoint; class GraphicsContextStateSaver; class PointerEventsHitRules; -class RenderSVGContainer; -class RenderSVGPath; -class RenderSVGResource; class SVGGraphicsElement; class RenderSVGShape : public RenderSVGModelObject { @@ -51,7 +48,6 @@ public: void setNeedsShapeUpdate() { m_needsShapeUpdate = true; } virtual void setNeedsBoundariesUpdate() OVERRIDE FINAL { m_needsBoundariesUpdate = true; } - virtual bool needsBoundariesUpdate() OVERRIDE FINAL { return m_needsBoundariesUpdate; } virtual void setNeedsTransformUpdate() OVERRIDE FINAL { m_needsTransformUpdate = true; } virtual void fillShape(GraphicsContext*) const; virtual void strokeShape(GraphicsContext*) const; @@ -66,7 +62,7 @@ public: protected: virtual void updateShapeFromElement(); - virtual bool isEmpty() const; + virtual bool isShapeEmpty() const { return path().isEmpty(); } virtual bool shapeDependentStrokeContains(const FloatPoint&); virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const; float strokeWidth() const; @@ -85,12 +81,12 @@ private: bool fillContains(const FloatPoint&, bool requiresFill = true, const WindRule fillRule = RULE_NONZERO); bool strokeContains(const FloatPoint&, bool requiresStroke = true); - virtual FloatRect repaintRectInLocalCoordinates() const OVERRIDE FINAL { return m_repaintBoundingBox; } + virtual FloatRect paintInvalidationRectInLocalCoordinates() const OVERRIDE FINAL { return m_repaintBoundingBox; } virtual const AffineTransform& localToParentTransform() const OVERRIDE FINAL { return m_localTransform; } virtual AffineTransform localTransform() const OVERRIDE FINAL { return m_localTransform; } virtual bool isSVGShape() const OVERRIDE FINAL { return true; } - virtual const char* renderName() const { return "RenderSVGShape"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGShape"; } virtual void layout() OVERRIDE FINAL; virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE FINAL; @@ -116,7 +112,6 @@ private: private: FloatRect m_repaintBoundingBox; - FloatRect m_repaintBoundingBoxExcludingShadow; AffineTransform m_localTransform; OwnPtr<Path> m_path; Vector<MarkerPosition> m_markerPositions; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTSpan.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTSpan.cpp index 5f34538620b..30c06454d59 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTSpan.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTSpan.cpp @@ -24,6 +24,9 @@ #include "core/rendering/svg/RenderSVGTSpan.h" +#include "core/rendering/svg/SVGRenderSupport.h" +#include "core/svg/SVGAltGlyphElement.h" + namespace WebCore { RenderSVGTSpan::RenderSVGTSpan(Element* element) @@ -31,4 +34,20 @@ RenderSVGTSpan::RenderSVGTSpan(Element* element) { } +bool RenderSVGTSpan::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + // Always allow text (except empty textnodes and <br>). + if (child->isText()) + return SVGRenderSupport::isRenderableTextNode(child); + +#if ENABLE(SVG_FONTS) + // Only allow other types of children if this is not an 'altGlyph'. + ASSERT(node()); + if (isSVGAltGlyphElement(*node())) + return false; +#endif + + return child->isSVGInline() && !child->isSVGTextPath(); +} + } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTSpan.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTSpan.h index ba8cb31e1e0..7875119a34f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTSpan.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTSpan.h @@ -28,7 +28,10 @@ namespace WebCore { class RenderSVGTSpan FINAL : public RenderSVGInline { public: explicit RenderSVGTSpan(Element*); - virtual const char* renderName() const { return "RenderSVGTSpan"; } + + virtual bool isChildAllowed(RenderObject* child, RenderStyle*) const OVERRIDE; + + virtual const char* renderName() const OVERRIDE { return "RenderSVGTSpan"; } }; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGText.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGText.cpp index ba45ce98f18..8536029524b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGText.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGText.cpp @@ -30,10 +30,11 @@ #include "core/rendering/HitTestRequest.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/LayoutRepainter.h" +#include "core/rendering/PaintInfo.h" #include "core/rendering/PointerEventsHitRules.h" #include "core/rendering/style/ShadowList.h" +#include "core/rendering/svg/RenderSVGInline.h" #include "core/rendering/svg/RenderSVGInlineText.h" #include "core/rendering/svg/RenderSVGResource.h" #include "core/rendering/svg/RenderSVGRoot.h" @@ -70,7 +71,7 @@ RenderSVGText::~RenderSVGText() bool RenderSVGText::isChildAllowed(RenderObject* child, RenderStyle*) const { - return child->isInline() && !SVGRenderSupport::isEmptySVGInlineText(child); + return child->isSVGInline() || (child->isText() && SVGRenderSupport::isRenderableTextNode(child)); } RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(RenderObject* start) @@ -93,33 +94,13 @@ const RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(const RenderObje return toRenderSVGText(start); } -LayoutRect RenderSVGText::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const -{ - return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer); -} - -void RenderSVGText::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const +void RenderSVGText::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, bool fixed) const { FloatRect repaintRect = rect; - computeFloatRectForRepaint(repaintContainer, repaintRect, fixed); + computeFloatRectForPaintInvalidation(paintInvalidationContainer, repaintRect, fixed); rect = enclosingLayoutRect(repaintRect); } -void RenderSVGText::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const -{ - SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaintRect, fixed); -} - -void RenderSVGText::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const -{ - SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed); -} - -const RenderObject* RenderSVGText::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const -{ - return SVGRenderSupport::pushMappingToContainer(this, ancestorToStopAt, geometryMap); -} - static inline void collectLayoutAttributes(RenderObject* text, Vector<SVGTextLayoutAttributes*>& attributes) { for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) { @@ -128,14 +109,15 @@ static inline void collectLayoutAttributes(RenderObject* text, Vector<SVGTextLay } } -static inline bool findPreviousAndNextAttributes(RenderObject* start, RenderSVGInlineText* locateElement, bool& stopAfterNext, SVGTextLayoutAttributes*& previous, SVGTextLayoutAttributes*& next) +static inline bool findPreviousAndNextAttributes(RenderSVGText* root, RenderSVGInlineText* locateElement, SVGTextLayoutAttributes*& previous, SVGTextLayoutAttributes*& next) { - ASSERT(start); + ASSERT(root); ASSERT(locateElement); - // FIXME: Make this iterative. - for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { - if (child->isSVGInlineText()) { - RenderSVGInlineText* text = toRenderSVGInlineText(child); + bool stopAfterNext = false; + RenderObject* current = root->firstChild(); + while (current) { + if (current->isSVGInlineText()) { + RenderSVGInlineText* text = toRenderSVGInlineText(current); if (locateElement != text) { if (stopAfterNext) { next = text->layoutAttributes(); @@ -143,20 +125,19 @@ static inline bool findPreviousAndNextAttributes(RenderObject* start, RenderSVGI } previous = text->layoutAttributes(); + } else { + stopAfterNext = true; + } + } else if (current->isSVGInline()) { + // Descend into text content (if possible). + if (RenderObject* child = toRenderSVGInline(current)->firstChild()) { + current = child; continue; } - - stopAfterNext = true; - continue; } - if (!child->isSVGInline()) - continue; - - if (findPreviousAndNextAttributes(child, locateElement, stopAfterNext, previous, next)) - return true; + current = current->nextInPreOrderAfterChildren(root); } - return false; } @@ -201,11 +182,10 @@ void RenderSVGText::subtreeChildWasAdded(RenderObject* child) attributes = newLayoutAttributes[i]; if (m_layoutAttributes.find(attributes) == kNotFound) { // Every time this is invoked, there's only a single new entry in the newLayoutAttributes list, compared to the old in m_layoutAttributes. - bool stopAfterNext = false; SVGTextLayoutAttributes* previous = 0; SVGTextLayoutAttributes* next = 0; ASSERT_UNUSED(child, attributes->context() == child); - findPreviousAndNextAttributes(this, attributes->context(), stopAfterNext, previous, next); + findPreviousAndNextAttributes(this, attributes->context(), previous, next); if (previous) m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(previous->context()); @@ -258,11 +238,10 @@ void RenderSVGText::subtreeChildWillBeRemoved(RenderObject* child, Vector<SVGTex // This logic requires that the 'text' child is still inserted in the tree. RenderSVGInlineText* text = toRenderSVGInlineText(child); - bool stopAfterNext = false; SVGTextLayoutAttributes* previous = 0; SVGTextLayoutAttributes* next = 0; if (!documentBeingDestroyed()) - findPreviousAndNextAttributes(this, text, stopAfterNext, previous, next); + findPreviousAndNextAttributes(this, text, previous, next); if (previous) affectedAttributes.append(previous); @@ -288,9 +267,8 @@ void RenderSVGText::subtreeChildWasRemoved(const Vector<SVGTextLayoutAttributes* m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(affectedAttributes[i]->context()); } -void RenderSVGText::subtreeStyleDidChange(RenderSVGInlineText* text) +void RenderSVGText::subtreeStyleDidChange() { - ASSERT(text); if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) return; @@ -299,7 +277,7 @@ void RenderSVGText::subtreeStyleDidChange(RenderSVGInlineText* text) // Only update the metrics cache, but not the text positioning element cache // nor the layout attributes cached in the leaf #text renderers. FontCachePurgePreventer fontCachePurgePreventer; - for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) { + for (RenderObject* descendant = firstChild(); descendant; descendant = descendant->nextInPreOrder(this)) { if (descendant->isSVGInlineText()) m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(toRenderSVGInlineText(descendant)); } @@ -344,7 +322,9 @@ static inline void updateFontInAllDescendants(RenderObject* start, SVGTextLayout void RenderSVGText::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); + + subtreeStyleDidChange(); + LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(this)); bool updateCachedBoundariesInParents = false; @@ -408,7 +388,16 @@ void RenderSVGText::layout() // FIXME: We need to find a way to only layout the child boxes, if needed. FloatRect oldBoundaries = objectBoundingBox(); ASSERT(childrenInline()); - forceLayoutInlineChildren(); + + rebuildFloatsFromIntruding(); + + LayoutUnit beforeEdge = borderBefore() + paddingBefore(); + LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight(); + setLogicalHeight(beforeEdge); + + LayoutUnit repaintLogicalTop = 0; + LayoutUnit repaintLogicalBottom = 0; + layoutInlineChildren(true, repaintLogicalTop, repaintLogicalBottom, afterEdge); if (m_needsReordering) m_needsReordering = false; @@ -430,7 +419,7 @@ void RenderSVGText::layout() RootInlineBox* RenderSVGText::createRootInlineBox() { - RootInlineBox* box = new SVGRootInlineBox(this); + RootInlineBox* box = new SVGRootInlineBox(*this); box->setHasVirtualLogicalHeight(); return box; } @@ -458,12 +447,6 @@ bool RenderSVGText::nodeAtFloatPoint(const HitTestRequest& request, HitTestResul return false; } -bool RenderSVGText::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint&, HitTestAction) -{ - ASSERT_NOT_REACHED(); - return false; -} - PositionWithAffinity RenderSVGText::positionForPoint(const LayoutPoint& pointInContents) { RootInlineBox* rootBox = firstRootBox(); @@ -477,7 +460,7 @@ PositionWithAffinity RenderSVGText::positionForPoint(const LayoutPoint& pointInC if (!closestBox) return createPositionWithAffinity(0, DOWNSTREAM); - return closestBox->renderer()->positionForPoint(LayoutPoint(pointInContents.x(), closestBox->y())); + return closestBox->renderer().positionForPoint(LayoutPoint(pointInContents.x(), closestBox->y())); } void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const @@ -491,14 +474,23 @@ void RenderSVGText::paint(PaintInfo& paintInfo, const LayoutPoint&) return; if (paintInfo.phase != PaintPhaseForeground - && paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseSelection) return; PaintInfo blockInfo(paintInfo); - GraphicsContextStateSaver stateSaver(*blockInfo.context); - blockInfo.applyTransform(localToParentTransform()); + GraphicsContextStateSaver stateSaver(*blockInfo.context, false); + const AffineTransform& localTransform = localToParentTransform(); + if (!localTransform.isIdentity()) { + stateSaver.save(); + blockInfo.applyTransform(localTransform, false); + } RenderBlock::paint(blockInfo, LayoutPoint()); + + // Paint the outlines, if any + if (paintInfo.phase == PaintPhaseForeground) { + blockInfo.phase = PaintPhaseSelfOutline; + RenderBlock::paint(blockInfo, LayoutPoint()); + } } FloatRect RenderSVGText::strokeBoundingBox() const @@ -511,11 +503,11 @@ FloatRect RenderSVGText::strokeBoundingBox() const ASSERT(node()); ASSERT(node()->isSVGElement()); SVGLengthContext lengthContext(toSVGElement(node())); - strokeBoundaries.inflate(svgStyle->strokeWidth().value(lengthContext)); + strokeBoundaries.inflate(svgStyle->strokeWidth()->value(lengthContext)); return strokeBoundaries; } -FloatRect RenderSVGText::repaintRectInLocalCoordinates() const +FloatRect RenderSVGText::paintInvalidationRectInLocalCoordinates() const { FloatRect repaintRect = strokeBoundingBox(); SVGRenderSupport::intersectRepaintRectWithResources(this, repaintRect); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGText.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGText.h index 56fb0db8e49..dfac5394a68 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGText.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGText.h @@ -37,12 +37,12 @@ public: explicit RenderSVGText(SVGTextElement*); virtual ~RenderSVGText(); - virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; void setNeedsPositioningValuesUpdate() { m_needsPositioningValuesUpdate = true; } - virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } + virtual void setNeedsTransformUpdate() OVERRIDE { m_needsTransformUpdate = true; } void setNeedsTextMetricsUpdate() { m_needsTextMetricsUpdate = true; } - virtual FloatRect repaintRectInLocalCoordinates() const; + virtual FloatRect paintInvalidationRectInLocalCoordinates() const OVERRIDE; static RenderSVGText* locateRenderSVGTextAncestor(RenderObject*); static const RenderSVGText* locateRenderSVGTextAncestor(const RenderObject*); @@ -53,42 +53,35 @@ public: void subtreeChildWasAdded(RenderObject*); void subtreeChildWillBeRemoved(RenderObject*, Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes); void subtreeChildWasRemoved(const Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes); - void subtreeStyleDidChange(RenderSVGInlineText*); + void subtreeStyleDidChange(); void subtreeTextDidChange(RenderSVGInlineText*); private: - virtual const char* renderName() const { return "RenderSVGText"; } - virtual bool isSVGText() const { return true; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGText"; } + virtual bool isSVGText() const OVERRIDE { return true; } - virtual void paint(PaintInfo&, const LayoutPoint&); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; - virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); - virtual PositionWithAffinity positionForPoint(const LayoutPoint&) OVERRIDE FINAL; + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; + virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) OVERRIDE; + virtual PositionWithAffinity positionForPoint(const LayoutPoint&) OVERRIDE; - virtual bool requiresLayer() const { return false; } - virtual void layout(); + virtual void layout() OVERRIDE; - virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; + virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const OVERRIDE; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE; - virtual void computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect&, bool fixed = false) const OVERRIDE; - virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed = false) const OVERRIDE; + virtual void mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect&, bool fixed = false) const OVERRIDE; - virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE; - virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE; - virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); + virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE; virtual void removeChild(RenderObject*) OVERRIDE; virtual void willBeDestroyed() OVERRIDE; - virtual FloatRect objectBoundingBox() const { return frameRect(); } - virtual FloatRect strokeBoundingBox() const; + virtual FloatRect objectBoundingBox() const OVERRIDE { return frameRect(); } + virtual FloatRect strokeBoundingBox() const OVERRIDE; - virtual const AffineTransform& localToParentTransform() const { return m_localTransform; } - virtual AffineTransform localTransform() const { return m_localTransform; } - virtual RootInlineBox* createRootInlineBox(); + virtual const AffineTransform& localToParentTransform() const OVERRIDE { return m_localTransform; } + virtual RootInlineBox* createRootInlineBox() OVERRIDE; - virtual RenderBlock* firstLineBlock() const; - virtual void updateFirstLetter(); + virtual RenderBlock* firstLineBlock() const OVERRIDE; + virtual void updateFirstLetter() OVERRIDE; bool shouldHandleSubtreeMutations() const; @@ -96,7 +89,6 @@ private: bool m_needsPositioningValuesUpdate : 1; bool m_needsTransformUpdate : 1; bool m_needsTextMetricsUpdate : 1; - AffineTransform m_localTransform; SVGTextLayoutAttributesBuilder m_layoutAttributesBuilder; Vector<SVGTextLayoutAttributes*> m_layoutAttributes; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTextPath.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTextPath.cpp index aec2da5ac29..f9deafa7276 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTextPath.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTextPath.cpp @@ -21,8 +21,8 @@ #include "core/rendering/svg/RenderSVGTextPath.h" -#include "SVGNames.h" #include "core/rendering/svg/SVGPathData.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/svg/SVGPathElement.h" #include "core/svg/SVGTextPathElement.h" @@ -33,30 +33,45 @@ RenderSVGTextPath::RenderSVGTextPath(Element* element) { } +bool RenderSVGTextPath::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + if (child->isText()) + return SVGRenderSupport::isRenderableTextNode(child); + +#if ENABLE(SVG_FONTS) + // 'altGlyph' is supported by the content model for 'textPath', but... + ASSERT(child->node()); + if (isSVGAltGlyphElement(*child->node())) + return false; +#endif + + return child->isSVGInline() && !child->isSVGTextPath(); +} + Path RenderSVGTextPath::layoutPath() const { SVGTextPathElement* textPathElement = toSVGTextPathElement(node()); - Element* targetElement = SVGURIReference::targetElementFromIRIString(textPathElement->hrefCurrentValue(), textPathElement->document()); - if (!targetElement || !targetElement->hasTagName(SVGNames::pathTag)) + Element* targetElement = SVGURIReference::targetElementFromIRIString(textPathElement->href()->currentValue()->value(), textPathElement->treeScope()); + if (!isSVGPathElement(targetElement)) return Path(); - SVGPathElement* pathElement = toSVGPathElement(targetElement); + SVGPathElement& pathElement = toSVGPathElement(*targetElement); Path pathData; - updatePathFromGraphicsElement(pathElement, pathData); + updatePathFromGraphicsElement(&pathElement, pathData); // Spec: The transform attribute on the referenced 'path' element represents a // supplemental transformation relative to the current user coordinate system for // the current 'text' element, including any adjustments to the current user coordinate // system due to a possible transform attribute on the current 'text' element. // http://www.w3.org/TR/SVG/text.html#TextPathElement - pathData.transform(pathElement->animatedLocalTransform()); + pathData.transform(pathElement.animatedLocalTransform()); return pathData; } float RenderSVGTextPath::startOffset() const { - return toSVGTextPathElement(node())->startOffsetCurrentValue().valueAsPercentage(); + return toSVGTextPathElement(node())->startOffset()->currentValue()->valueAsPercentage(); } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTextPath.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTextPath.h index 6e14b5528f6..6d98871341f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTextPath.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTextPath.h @@ -32,10 +32,12 @@ public: Path layoutPath() const; float startOffset() const; - virtual bool isSVGTextPath() const { return true; } + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; + + virtual bool isSVGTextPath() const OVERRIDE { return true; } private: - virtual const char* renderName() const { return "RenderSVGTextPath"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGTextPath"; } Path m_layoutPath; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTransformableContainer.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTransformableContainer.cpp index 52516c4c268..841bec55ec1 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTransformableContainer.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTransformableContainer.cpp @@ -23,8 +23,8 @@ #include "core/rendering/svg/RenderSVGTransformableContainer.h" -#include "SVGNames.h" #include "core/rendering/svg/SVGRenderSupport.h" +#include "core/svg/SVGGElement.h" #include "core/svg/SVGGraphicsElement.h" #include "core/svg/SVGUseElement.h" @@ -37,25 +37,60 @@ RenderSVGTransformableContainer::RenderSVGTransformableContainer(SVGGraphicsElem { } +static bool hasValidPredecessor(const Node* node) +{ + ASSERT(node); + while ((node = node->previousSibling())) { + if (node->isSVGElement() && toSVGElement(node)->isValid()) + return true; + } + return false; +} + +bool RenderSVGTransformableContainer::isChildAllowed(RenderObject* child, RenderStyle* style) const +{ + ASSERT(element()); + if (isSVGSwitchElement(*element())) { + Node* node = child->node(); + // Reject non-SVG/non-valid elements. + if (!node->isSVGElement() || !toSVGElement(node)->isValid()) + return false; + // Reject this child if it isn't the first valid node. + if (hasValidPredecessor(node)) + return false; + } else if (isSVGAElement(*element())) { + // http://www.w3.org/2003/01/REC-SVG11-20030114-errata#linking-text-environment + // The 'a' element may contain any element that its parent may contain, except itself. + if (isSVGAElement(*child->node())) + return false; + if (parent() && parent()->isSVG()) + return parent()->isChildAllowed(child, style); + } + return RenderSVGContainer::isChildAllowed(child, style); +} + bool RenderSVGTransformableContainer::calculateLocalTransform() { SVGGraphicsElement* element = toSVGGraphicsElement(this->element()); + ASSERT(element); // If we're either the renderer for a <use> element, or for any <g> element inside the shadow // tree, that was created during the use/symbol/svg expansion in SVGUseElement. These containers // need to respect the translations induced by their corresponding use elements x/y attributes. SVGUseElement* useElement = 0; - if (element->hasTagName(SVGNames::useTag)) + if (isSVGUseElement(*element)) { useElement = toSVGUseElement(element); - else if (element->isInShadowTree() && element->hasTagName(SVGNames::gTag)) { + } else if (isSVGGElement(*element) && toSVGGElement(element)->inUseShadowTree()) { SVGElement* correspondingElement = element->correspondingElement(); - if (correspondingElement && correspondingElement->hasTagName(SVGNames::useTag)) + if (isSVGUseElement(correspondingElement)) useElement = toSVGUseElement(correspondingElement); } if (useElement) { SVGLengthContext lengthContext(useElement); - FloatSize translation(useElement->xCurrentValue().value(lengthContext), useElement->yCurrentValue().value(lengthContext)); + FloatSize translation( + useElement->x()->currentValue()->value(lengthContext), + useElement->y()->currentValue()->value(lengthContext)); if (translation != m_lastTranslation) m_needsTransformUpdate = true; m_lastTranslation = translation; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTransformableContainer.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTransformableContainer.h index 6aa752aa95d..4b03d8a330d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTransformableContainer.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTransformableContainer.h @@ -30,14 +30,16 @@ class RenderSVGTransformableContainer FINAL : public RenderSVGContainer { public: explicit RenderSVGTransformableContainer(SVGGraphicsElement*); - virtual bool isSVGTransformableContainer() const { return true; } - virtual const AffineTransform& localToParentTransform() const { return m_localTransform; } - virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } - virtual bool didTransformToRootUpdate() { return m_didTransformToRootUpdate; } + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; + + virtual bool isSVGTransformableContainer() const OVERRIDE { return true; } + virtual const AffineTransform& localToParentTransform() const OVERRIDE { return m_localTransform; } + virtual void setNeedsTransformUpdate() OVERRIDE { m_needsTransformUpdate = true; } + virtual bool didTransformToRootUpdate() OVERRIDE { return m_didTransformToRootUpdate; } private: - virtual bool calculateLocalTransform(); - virtual AffineTransform localTransform() const { return m_localTransform; } + virtual bool calculateLocalTransform() OVERRIDE; + virtual AffineTransform localTransform() const OVERRIDE { return m_localTransform; } bool m_needsTransformUpdate : 1; bool m_didTransformToRootUpdate : 1; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGViewportContainer.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGViewportContainer.cpp index 05234c18b57..4b4d3d5d4c3 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGViewportContainer.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGViewportContainer.cpp @@ -21,11 +21,10 @@ */ #include "config.h" - #include "core/rendering/svg/RenderSVGViewportContainer.h" -#include "SVGNames.h" -#include "core/svg/SVGElementInstance.h" +#include "core/rendering/PaintInfo.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/svg/SVGSVGElement.h" #include "core/svg/SVGUseElement.h" #include "platform/graphics/GraphicsContext.h" @@ -42,7 +41,8 @@ RenderSVGViewportContainer::RenderSVGViewportContainer(SVGElement* node) void RenderSVGViewportContainer::determineIfLayoutSizeChanged() { - if (!element()->hasTagName(SVGNames::svgTag)) + ASSERT(element()); + if (!isSVGSVGElement(*element())) return; m_isLayoutSizeChanged = toSVGSVGElement(element())->hasRelativeLengths() && selfNeedsLayout(); @@ -57,59 +57,14 @@ void RenderSVGViewportContainer::applyViewportClip(PaintInfo& paintInfo) void RenderSVGViewportContainer::calcViewport() { SVGElement* element = this->element(); - if (!element->hasTagName(SVGNames::svgTag)) + ASSERT(element); + if (!isSVGSVGElement(*element)) return; SVGSVGElement* svg = toSVGSVGElement(element); FloatRect oldViewport = m_viewport; SVGLengthContext lengthContext(element); - m_viewport = FloatRect(svg->xCurrentValue().value(lengthContext), svg->yCurrentValue().value(lengthContext), svg->widthCurrentValue().value(lengthContext), svg->heightCurrentValue().value(lengthContext)); - - SVGElement* correspondingElement = svg->correspondingElement(); - if (correspondingElement && svg->isInShadowTree()) { - const HashSet<SVGElementInstance*>& instances = correspondingElement->instancesForElement(); - ASSERT(!instances.isEmpty()); - - SVGUseElement* useElement = 0; - const HashSet<SVGElementInstance*>::const_iterator end = instances.end(); - for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) { - const SVGElementInstance* instance = (*it); - ASSERT(instance->correspondingElement()->hasTagName(SVGNames::svgTag) || instance->correspondingElement()->hasTagName(SVGNames::symbolTag)); - if (instance->shadowTreeElement() == svg) { - ASSERT(correspondingElement == instance->correspondingElement()); - useElement = instance->directUseElement(); - if (!useElement) - useElement = instance->correspondingUseElement(); - break; - } - } - - ASSERT(useElement); - bool isSymbolElement = correspondingElement->hasTagName(SVGNames::symbolTag); - - // Spec (<use> on <symbol>): This generated 'svg' will always have explicit values for attributes width and height. - // If attributes width and/or height are provided on the 'use' element, then these attributes - // will be transferred to the generated 'svg'. If attributes width and/or height are not specified, - // the generated 'svg' element will use values of 100% for these attributes. - - // Spec (<use> on <svg>): If attributes width and/or height are provided on the 'use' element, then these - // values will override the corresponding attributes on the 'svg' in the generated tree. - - SVGLengthContext lengthContext(element); - if (useElement->hasAttribute(SVGNames::widthAttr)) - m_viewport.setWidth(useElement->widthCurrentValue().value(lengthContext)); - else if (isSymbolElement && svg->hasAttribute(SVGNames::widthAttr)) { - SVGLength containerWidth(LengthModeWidth, "100%"); - m_viewport.setWidth(containerWidth.value(lengthContext)); - } - - if (useElement->hasAttribute(SVGNames::heightAttr)) - m_viewport.setHeight(useElement->heightCurrentValue().value(lengthContext)); - else if (isSymbolElement && svg->hasAttribute(SVGNames::heightAttr)) { - SVGLength containerHeight(LengthModeHeight, "100%"); - m_viewport.setHeight(containerHeight.value(lengthContext)); - } - } + m_viewport = FloatRect(svg->x()->currentValue()->value(lengthContext), svg->y()->currentValue()->value(lengthContext), svg->width()->currentValue()->value(lengthContext), svg->height()->currentValue()->value(lengthContext)); if (oldViewport != m_viewport) { setNeedsBoundariesUpdate(); @@ -130,7 +85,8 @@ bool RenderSVGViewportContainer::calculateLocalTransform() AffineTransform RenderSVGViewportContainer::viewportTransform() const { - if (element()->hasTagName(SVGNames::svgTag)) { + ASSERT(element()); + if (isSVGSVGElement(*element())) { SVGSVGElement* svg = toSVGSVGElement(element()); return svg->viewBoxToViewTransform(m_viewport.width(), m_viewport.height()); } @@ -149,11 +105,10 @@ bool RenderSVGViewportContainer::pointIsInsideViewportClip(const FloatPoint& poi void RenderSVGViewportContainer::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { + ASSERT(element()); // An empty viewBox disables rendering. - if (element()->hasTagName(SVGNames::svgTag)) { - if (toSVGSVGElement(element())->hasEmptyViewBox()) - return; - } + if (isSVGSVGElement(*element()) && toSVGSVGElement(*element()).hasEmptyViewBox()) + return; RenderSVGContainer::paint(paintInfo, paintOffset); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGViewportContainer.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGViewportContainer.h index b1b79ed5e31..679bd051dc7 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGViewportContainer.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGViewportContainer.h @@ -35,25 +35,25 @@ public: FloatRect viewport() const { return m_viewport; } bool isLayoutSizeChanged() const { return m_isLayoutSizeChanged; } - virtual bool didTransformToRootUpdate() { return m_didTransformToRootUpdate; } + virtual bool didTransformToRootUpdate() OVERRIDE { return m_didTransformToRootUpdate; } - virtual void determineIfLayoutSizeChanged(); - virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } + virtual void determineIfLayoutSizeChanged() OVERRIDE; + virtual void setNeedsTransformUpdate() OVERRIDE { m_needsTransformUpdate = true; } virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; private: - virtual bool isSVGViewportContainer() const { return true; } - virtual const char* renderName() const { return "RenderSVGViewportContainer"; } + virtual bool isSVGViewportContainer() const OVERRIDE { return true; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGViewportContainer"; } AffineTransform viewportTransform() const; - virtual const AffineTransform& localToParentTransform() const { return m_localToParentTransform; } + virtual const AffineTransform& localToParentTransform() const OVERRIDE { return m_localToParentTransform; } - virtual void calcViewport(); - virtual bool calculateLocalTransform(); + virtual void calcViewport() OVERRIDE; + virtual bool calculateLocalTransform() OVERRIDE; - virtual void applyViewportClip(PaintInfo&); - virtual bool pointIsInsideViewportClip(const FloatPoint& pointInParent); + virtual void applyViewportClip(PaintInfo&) OVERRIDE; + virtual bool pointIsInsideViewportClip(const FloatPoint& pointInParent) OVERRIDE; FloatRect m_viewport; mutable AffineTransform m_localToParentTransform; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineFlowBox.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineFlowBox.cpp index c4f5cdb1203..d4a861c3db2 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineFlowBox.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineFlowBox.cpp @@ -23,8 +23,6 @@ #include "config.h" #include "core/rendering/svg/SVGInlineFlowBox.h" -#include "core/dom/DocumentMarkerController.h" -#include "core/dom/RenderedDocumentMarker.h" #include "core/rendering/svg/RenderSVGInlineText.h" #include "core/rendering/svg/SVGInlineTextBox.h" #include "core/rendering/svg/SVGRenderingContext.h" @@ -47,22 +45,15 @@ void SVGInlineFlowBox::paintSelectionBackground(PaintInfo& paintInfo) } } -void SVGInlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUnit, LayoutUnit) +void SVGInlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit, LayoutUnit) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(!paintInfo.context->paintingDisabled()); - RenderObject* boxRenderer = renderer(); - ASSERT(boxRenderer); - - SVGRenderingContext renderingContext(boxRenderer, paintInfo, SVGRenderingContext::SaveGraphicsContext); + SVGRenderingContext renderingContext(&renderer(), paintInfo, SVGRenderingContext::SaveGraphicsContext); if (renderingContext.isRenderingPrepared()) { - for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { - if (child->isSVGInlineTextBox()) - computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(toSVGInlineTextBox(child)->textRenderer())); - - child->paint(paintInfo, LayoutPoint(), 0, 0); - } + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) + child->paint(paintInfo, paintOffset, 0, 0); } } @@ -77,66 +68,4 @@ FloatRect SVGInlineFlowBox::calculateBoundaries() const return childRect; } -void SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(RenderSVGInlineText* textRenderer) -{ - ASSERT(textRenderer); - - Node* node = textRenderer->node(); - if (!node || !node->inDocument()) - return; - - RenderStyle* style = textRenderer->style(); - ASSERT(style); - - AffineTransform fragmentTransform; - Document& document = textRenderer->document(); - Vector<DocumentMarker*> markers = document.markers()->markersFor(textRenderer->node()); - - Vector<DocumentMarker*>::iterator markerEnd = markers.end(); - for (Vector<DocumentMarker*>::iterator markerIt = markers.begin(); markerIt != markerEnd; ++markerIt) { - DocumentMarker* marker = *markerIt; - - // SVG is only interessted in the TextMatch marker, for now. - if (marker->type() != DocumentMarker::TextMatch) - continue; - - FloatRect markerRect; - for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { - if (!box->isSVGInlineTextBox()) - continue; - - SVGInlineTextBox* textBox = toSVGInlineTextBox(box); - - int markerStartPosition = max<int>(marker->startOffset() - textBox->start(), 0); - int markerEndPosition = min<int>(marker->endOffset() - textBox->start(), textBox->len()); - - if (markerStartPosition >= markerEndPosition) - continue; - - int fragmentStartPosition = 0; - int fragmentEndPosition = 0; - - const Vector<SVGTextFragment>& fragments = textBox->textFragments(); - unsigned textFragmentsSize = fragments.size(); - for (unsigned i = 0; i < textFragmentsSize; ++i) { - const SVGTextFragment& fragment = fragments.at(i); - - fragmentStartPosition = markerStartPosition; - fragmentEndPosition = markerEndPosition; - if (!textBox->mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition)) - continue; - - FloatRect fragmentRect = textBox->selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style); - fragment.buildFragmentTransform(fragmentTransform); - if (!fragmentTransform.isIdentity()) - fragmentRect = fragmentTransform.mapRect(fragmentRect); - - markerRect.unite(fragmentRect); - } - } - - toRenderedDocumentMarker(marker)->setRenderedRect(textRenderer->localToAbsoluteQuad(markerRect).enclosingBoundingBox()); - } -} - } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineFlowBox.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineFlowBox.h index e76a9ccdafc..0d66044e42b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineFlowBox.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineFlowBox.h @@ -25,26 +25,22 @@ namespace WebCore { -class RenderSVGInlineText; - class SVGInlineFlowBox FINAL : public InlineFlowBox { public: - SVGInlineFlowBox(RenderObject* obj) + SVGInlineFlowBox(RenderObject& obj) : InlineFlowBox(obj) , m_logicalHeight(0) { } - virtual bool isSVGInlineFlowBox() const { return true; } - virtual float virtualLogicalHeight() const { return m_logicalHeight; } + virtual bool isSVGInlineFlowBox() const OVERRIDE { return true; } + virtual float virtualLogicalHeight() const OVERRIDE { return m_logicalHeight; } void setLogicalHeight(float h) { m_logicalHeight = h; } void paintSelectionBackground(PaintInfo&); - virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); - - virtual FloatRect calculateBoundaries() const; + virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; - static void computeTextMatchMarkerRectForRenderer(RenderSVGInlineText*); + virtual FloatRect calculateBoundaries() const OVERRIDE; private: float m_logicalHeight; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineTextBox.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineTextBox.cpp index 6c593827328..a5dc2fc742c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineTextBox.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineTextBox.cpp @@ -22,11 +22,17 @@ #include "config.h" #include "core/rendering/svg/SVGInlineTextBox.h" -#include "core/frame/Frame.h" +#include "core/dom/DocumentMarkerController.h" +#include "core/dom/RenderedDocumentMarker.h" +#include "core/editing/Editor.h" #include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/rendering/HitTestResult.h" #include "core/rendering/InlineFlowBox.h" +#include "core/rendering/PaintInfo.h" #include "core/rendering/PointerEventsHitRules.h" +#include "core/rendering/RenderInline.h" +#include "core/rendering/RenderTheme.h" #include "core/rendering/style/ShadowList.h" #include "core/rendering/svg/RenderSVGInlineText.h" #include "core/rendering/svg/RenderSVGResource.h" @@ -35,7 +41,7 @@ #include "core/rendering/svg/SVGTextRunRenderingContext.h" #include "platform/FloatConversion.h" #include "platform/fonts/FontCache.h" -#include "platform/graphics/DrawLooper.h" +#include "platform/graphics/DrawLooperBuilder.h" #include "platform/graphics/GraphicsContextStateSaver.h" using namespace std; @@ -44,17 +50,16 @@ namespace WebCore { struct ExpectedSVGInlineTextBoxSize : public InlineTextBox { float float1; - uint32_t bitfields : 5; + uint32_t bitfields : 1; void* pointer; Vector<SVGTextFragment> vector; }; COMPILE_ASSERT(sizeof(SVGInlineTextBox) == sizeof(ExpectedSVGInlineTextBoxSize), SVGInlineTextBox_is_not_of_expected_size); -SVGInlineTextBox::SVGInlineTextBox(RenderObject* object) +SVGInlineTextBox::SVGInlineTextBox(RenderObject& object) : InlineTextBox(object) , m_logicalHeight(0) - , m_paintingResourceMode(ApplyToDefaultMode) , m_startsNewTextChunk(false) , m_paintingResource(0) { @@ -84,13 +89,12 @@ int SVGInlineTextBox::offsetForPosition(float, bool) const int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragment, float position, bool includePartialGlyphs) const { - RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); - ASSERT(textRenderer); + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(this->textRenderer()); - float scalingFactor = textRenderer->scalingFactor(); + float scalingFactor = textRenderer.scalingFactor(); ASSERT(scalingFactor); - RenderStyle* style = textRenderer->style(); + RenderStyle* style = textRenderer.style(); ASSERT(style); TextRun textRun = constructTextRun(style, fragment); @@ -102,7 +106,7 @@ int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragmen if (!fragmentTransform.isIdentity()) textRun.setHorizontalGlyphStretch(narrowPrecisionToFloat(fragmentTransform.xScale())); - return fragment.characterOffset - start() + textRenderer->scaledFont().offsetForPosition(textRun, position * scalingFactor, includePartialGlyphs); + return fragment.characterOffset - start() + textRenderer.scaledFont().offsetForPosition(textRun, position * scalingFactor, includePartialGlyphs); } float SVGInlineTextBox::positionForOffset(int) const @@ -119,13 +123,12 @@ FloatRect SVGInlineTextBox::selectionRectForTextFragment(const SVGTextFragment& FontCachePurgePreventer fontCachePurgePreventer; - RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); - ASSERT(textRenderer); + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(this->textRenderer()); - float scalingFactor = textRenderer->scalingFactor(); + float scalingFactor = textRenderer.scalingFactor(); ASSERT(scalingFactor); - const Font& scaledFont = textRenderer->scaledFont(); + const Font& scaledFont = textRenderer.scaledFont(); const FontMetrics& scaledFontMetrics = scaledFont.fontMetrics(); FloatPoint textOrigin(fragment.x, fragment.y); if (scalingFactor != 1) @@ -149,10 +152,7 @@ LayoutRect SVGInlineTextBox::localSelectionRect(int startPosition, int endPositi if (startPosition >= endPosition) return LayoutRect(); - RenderText* text = textRenderer(); - ASSERT(text); - - RenderStyle* style = text->style(); + RenderStyle* style = textRenderer().style(); ASSERT(style); AffineTransform fragmentTransform; @@ -171,8 +171,7 @@ LayoutRect SVGInlineTextBox::localSelectionRect(int startPosition, int endPositi FloatRect fragmentRect = selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style); fragment.buildFragmentTransform(fragmentTransform); - if (!fragmentTransform.isIdentity()) - fragmentRect = fragmentTransform.mapRect(fragmentRect); + fragmentRect = fragmentTransform.mapRect(fragmentRect); selectionRect.unite(fragmentRect); } @@ -180,25 +179,24 @@ LayoutRect SVGInlineTextBox::localSelectionRect(int startPosition, int endPositi return enclosingIntRect(selectionRect); } -static inline bool textShouldBePainted(RenderSVGInlineText* textRenderer) +static inline bool textShouldBePainted(RenderSVGInlineText& textRenderer) { // Font::pixelSize(), returns FontDescription::computedPixelSize(), which returns "int(x + 0.5)". // If the absolute font size on screen is below x=0.5, don't render anything. - return textRenderer->scaledFont().pixelSize(); + return textRenderer.scaledFont().fontDescription().computedPixelSize(); } void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) { - ASSERT(paintInfo.shouldPaintWithinRoot(renderer())); + ASSERT(paintInfo.shouldPaintWithinRoot(&renderer())); ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(truncation() == cNoTruncation); - if (renderer()->style()->visibility() != VISIBLE) + if (renderer().style()->visibility() != VISIBLE) return; - RenderObject* parentRenderer = parent()->renderer(); - ASSERT(parentRenderer); - ASSERT(!parentRenderer->document().printing()); + RenderObject& parentRenderer = parent()->renderer(); + ASSERT(!parentRenderer.document().printing()); // Determine whether or not we're selected. bool paintSelectedTextOnly = paintInfo.phase == PaintPhaseSelection; @@ -206,25 +204,17 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) if (!hasSelection || paintSelectedTextOnly) return; - Color backgroundColor = renderer()->selectionBackgroundColor(); - if (!backgroundColor.isValid() || !backgroundColor.alpha()) + Color backgroundColor = renderer().selectionBackgroundColor(); + if (!backgroundColor.alpha()) return; - RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); - ASSERT(textRenderer); + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(this->textRenderer()); if (!textShouldBePainted(textRenderer)) return; - RenderStyle* style = parentRenderer->style(); + RenderStyle* style = parentRenderer.style(); ASSERT(style); - RenderStyle* selectionStyle = style; - if (hasSelection) { - selectionStyle = parentRenderer->getCachedPseudoStyle(SELECTION); - if (!selectionStyle) - selectionStyle = style; - } - int startPosition, endPosition; selectionStartEnd(startPosition, endPosition); @@ -248,41 +238,39 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) paintInfo.context->setFillColor(backgroundColor); paintInfo.context->fillRect(selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style), backgroundColor); - - m_paintingResourceMode = ApplyToDefaultMode; } ASSERT(!m_paintingResource); } -void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUnit, LayoutUnit) +void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit, LayoutUnit) { - ASSERT(paintInfo.shouldPaintWithinRoot(renderer())); + ASSERT(paintInfo.shouldPaintWithinRoot(&renderer())); ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(truncation() == cNoTruncation); - if (renderer()->style()->visibility() != VISIBLE) + if (renderer().style()->visibility() != VISIBLE) return; // Note: We're explicitely not supporting composition & custom underlines and custom highlighters - unlike InlineTextBox. // If we ever need that for SVG, it's very easy to refactor and reuse the code. - RenderObject* parentRenderer = parent()->renderer(); - ASSERT(parentRenderer); + RenderObject& parentRenderer = parent()->renderer(); bool paintSelectedTextOnly = paintInfo.phase == PaintPhaseSelection; - bool hasSelection = !parentRenderer->document().printing() && selectionState() != RenderObject::SelectionNone; + bool hasSelection = !parentRenderer.document().printing() && selectionState() != RenderObject::SelectionNone; if (!hasSelection && paintSelectedTextOnly) return; - RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); - ASSERT(textRenderer); + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(this->textRenderer()); if (!textShouldBePainted(textRenderer)) return; - RenderStyle* style = parentRenderer->style(); + RenderStyle* style = parentRenderer.style(); ASSERT(style); + paintDocumentMarkers(paintInfo.context, paintOffset, style, textRenderer.scaledFont(), true); + const SVGRenderStyle* svgStyle = style->svgStyle(); ASSERT(svgStyle); @@ -291,7 +279,7 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni RenderStyle* selectionStyle = style; if (hasSelection) { - selectionStyle = parentRenderer->getCachedPseudoStyle(SELECTION); + selectionStyle = parentRenderer.getCachedPseudoStyle(SELECTION); if (selectionStyle) { const SVGRenderStyle* svgSelectionStyle = selectionStyle->svgStyle(); ASSERT(svgSelectionStyle); @@ -300,11 +288,12 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni hasFill = svgSelectionStyle->hasFill(); if (!hasVisibleStroke) hasVisibleStroke = svgSelectionStyle->hasVisibleStroke(); - } else + } else { selectionStyle = style; + } } - if (textRenderer->frame() && textRenderer->frame()->view() && textRenderer->frame()->view()->paintBehavior() & PaintBehaviorRenderingSVGMask) { + if (textRenderer.frame() && textRenderer.frame()->view() && textRenderer.frame()->view()->paintBehavior() & PaintBehaviorRenderingSVGMask) { hasFill = true; hasVisibleStroke = false; } @@ -315,10 +304,12 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni SVGTextFragment& fragment = m_textFragments.at(i); ASSERT(!m_paintingResource); - GraphicsContextStateSaver stateSaver(*paintInfo.context); + GraphicsContextStateSaver stateSaver(*paintInfo.context, false); fragment.buildFragmentTransform(fragmentTransform); - if (!fragmentTransform.isIdentity()) + if (!fragmentTransform.isIdentity()) { + stateSaver.save(); paintInfo.context->concatCTM(fragmentTransform); + } // Spec: All text decorations except line-through should be drawn before the text is filled and stroked; thus, the text is rendered on top of these decorations. unsigned decorations = style->textDecorationsInEffect(); @@ -332,15 +323,15 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni case PT_FILL: // Fill text if (hasFill) { - m_paintingResourceMode = ApplyToFillMode | ApplyToTextMode; - paintText(paintInfo.context, style, selectionStyle, fragment, hasSelection, paintSelectedTextOnly); + paintText(paintInfo.context, style, selectionStyle, fragment, + ApplyToFillMode | ApplyToTextMode, hasSelection, paintSelectedTextOnly); } break; case PT_STROKE: // Stroke text if (hasVisibleStroke) { - m_paintingResourceMode = ApplyToStrokeMode | ApplyToTextMode; - paintText(paintInfo.context, style, selectionStyle, fragment, hasSelection, paintSelectedTextOnly); + paintText(paintInfo.context, style, selectionStyle, fragment, + ApplyToStrokeMode | ApplyToTextMode, hasSelection, paintSelectedTextOnly); } break; case PT_MARKERS: @@ -355,25 +346,29 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni // Spec: Line-through should be drawn after the text is filled and stroked; thus, the line-through is rendered on top of the text. if (decorations & TextDecorationLineThrough) paintDecoration(paintInfo.context, TextDecorationLineThrough, fragment); - - m_paintingResourceMode = ApplyToDefaultMode; } + // finally, paint the outline if any + if (style->hasOutline() && parentRenderer.isRenderInline()) + toRenderInline(parentRenderer).paintOutline(paintInfo, paintOffset); + ASSERT(!m_paintingResource); } -bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, float scalingFactor, RenderObject* renderer, RenderStyle* style) +bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, float scalingFactor, + RenderObject* renderer, RenderStyle* style, RenderSVGResourceModeFlags resourceMode) { + // Callers must save the context state before calling when scalingFactor is not 1. ASSERT(scalingFactor); ASSERT(renderer); ASSERT(style); - ASSERT(m_paintingResourceMode != ApplyToDefaultMode); + ASSERT(resourceMode != ApplyToDefaultMode); - Color fallbackColor; - if (m_paintingResourceMode & ApplyToFillMode) - m_paintingResource = RenderSVGResource::fillPaintingResource(renderer, style, fallbackColor); - else if (m_paintingResourceMode & ApplyToStrokeMode) - m_paintingResource = RenderSVGResource::strokePaintingResource(renderer, style, fallbackColor); + bool hasFallback = false; + if (resourceMode & ApplyToFillMode) + m_paintingResource = RenderSVGResource::fillPaintingResource(renderer, style, hasFallback); + else if (resourceMode & ApplyToStrokeMode) + m_paintingResource = RenderSVGResource::strokePaintingResource(renderer, style, hasFallback); else { // We're either called for stroking or filling. ASSERT_NOT_REACHED(); @@ -382,36 +377,32 @@ bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, float if (!m_paintingResource) return false; - if (!m_paintingResource->applyResource(renderer, style, context, m_paintingResourceMode)) { - if (fallbackColor.isValid()) { - RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource(); - fallbackResource->setColor(fallbackColor); - - m_paintingResource = fallbackResource; - m_paintingResource->applyResource(renderer, style, context, m_paintingResourceMode); + if (!m_paintingResource->applyResource(renderer, style, context, resourceMode)) { + if (hasFallback) { + m_paintingResource = RenderSVGResource::sharedSolidPaintingResource(); + m_paintingResource->applyResource(renderer, style, context, resourceMode); } } - if (scalingFactor != 1 && m_paintingResourceMode & ApplyToStrokeMode) + if (scalingFactor != 1 && resourceMode & ApplyToStrokeMode) context->setStrokeThickness(context->strokeThickness() * scalingFactor); return true; } -void SVGInlineTextBox::releasePaintingResource(GraphicsContext*& context, const Path* path) +void SVGInlineTextBox::releasePaintingResource(GraphicsContext*& context, const Path* path, + RenderSVGResourceModeFlags resourceMode) { ASSERT(m_paintingResource); - RenderObject* parentRenderer = parent()->renderer(); - ASSERT(parentRenderer); - - m_paintingResource->postApplyResource(parentRenderer, context, m_paintingResourceMode, path, /*RenderSVGShape*/ 0); + m_paintingResource->postApplyResource(&parent()->renderer(), context, resourceMode, path, 0); m_paintingResource = 0; } -bool SVGInlineTextBox::prepareGraphicsContextForTextPainting(GraphicsContext*& context, float scalingFactor, TextRun& textRun, RenderStyle* style) +bool SVGInlineTextBox::prepareGraphicsContextForTextPainting(GraphicsContext*& context, + float scalingFactor, TextRun& textRun, RenderStyle* style, RenderSVGResourceModeFlags resourceMode) { - bool acquiredResource = acquirePaintingResource(context, scalingFactor, parent()->renderer(), style); + bool acquiredResource = acquirePaintingResource(context, scalingFactor, &parent()->renderer(), style, resourceMode); if (!acquiredResource) return false; @@ -425,9 +416,10 @@ bool SVGInlineTextBox::prepareGraphicsContextForTextPainting(GraphicsContext*& c return true; } -void SVGInlineTextBox::restoreGraphicsContextAfterTextPainting(GraphicsContext*& context, TextRun& textRun) +void SVGInlineTextBox::restoreGraphicsContextAfterTextPainting(GraphicsContext*& context, + TextRun& textRun, RenderSVGResourceModeFlags resourceMode) { - releasePaintingResource(context, /* path */0); + releasePaintingResource(context, 0, resourceMode); #if ENABLE(SVG_FONTS) TextRun::RenderingContext* renderingContext = textRun.renderingContext(); @@ -439,10 +431,8 @@ void SVGInlineTextBox::restoreGraphicsContextAfterTextPainting(GraphicsContext*& TextRun SVGInlineTextBox::constructTextRun(RenderStyle* style, const SVGTextFragment& fragment) const { ASSERT(style); - ASSERT(textRenderer()); - RenderText* text = textRenderer(); - ASSERT(text); + RenderText* text = &textRenderer(); // FIXME(crbug.com/264211): This should not be necessary but can occur if we // layout during layout. Remove this when 264211 is fixed. @@ -523,7 +513,7 @@ static inline float thicknessForDecoration(TextDecoration, const Font& font) { // FIXME: For SVG Fonts we need to use the attributes defined in the <font-face> if specified. // Compatible with Batik/Opera - return font.size() / 20.0f; + return font.fontDescription().computedSize() / 20.0f; } static inline RenderObject* findRenderObjectDefininingTextDecoration(InlineFlowBox* parentBox) @@ -531,7 +521,7 @@ static inline RenderObject* findRenderObjectDefininingTextDecoration(InlineFlowB // Lookup first render object in parent hierarchy which has text-decoration set. RenderObject* renderer = 0; while (parentBox) { - renderer = parentBox->renderer(); + renderer = &parentBox->renderer(); if (renderer->style() && renderer->style()->textDecoration() != TextDecorationNone) break; @@ -545,7 +535,7 @@ static inline RenderObject* findRenderObjectDefininingTextDecoration(InlineFlowB void SVGInlineTextBox::paintDecoration(GraphicsContext* context, TextDecoration decoration, const SVGTextFragment& fragment) { - if (textRenderer()->style()->textDecorationsInEffect() == TextDecorationNone) + if (textRenderer().style()->textDecorationsInEffect() == TextDecorationNone) return; // Find out which render style defined the text-decoration, as its fill/stroke properties have to be used for drawing instead of ours. @@ -559,24 +549,29 @@ void SVGInlineTextBox::paintDecoration(GraphicsContext* context, TextDecoration const SVGRenderStyle* svgDecorationStyle = decorationStyle->svgStyle(); ASSERT(svgDecorationStyle); - bool hasDecorationFill = svgDecorationStyle->hasFill(); - bool hasVisibleDecorationStroke = svgDecorationStyle->hasVisibleStroke(); - - if (hasDecorationFill) { - m_paintingResourceMode = ApplyToFillMode; - paintDecorationWithStyle(context, decoration, fragment, decorationRenderer); - } - - if (hasVisibleDecorationStroke) { - m_paintingResourceMode = ApplyToStrokeMode; - paintDecorationWithStyle(context, decoration, fragment, decorationRenderer); + for (int i = 0; i < 3; i++) { + switch (svgDecorationStyle->paintOrderType(i)) { + case PT_FILL: + if (svgDecorationStyle->hasFill()) + paintDecorationWithStyle(context, decoration, fragment, decorationRenderer, ApplyToFillMode); + break; + case PT_STROKE: + if (svgDecorationStyle->hasVisibleStroke()) + paintDecorationWithStyle(context, decoration, fragment, decorationRenderer, ApplyToStrokeMode); + break; + case PT_MARKERS: + break; + default: + ASSERT_NOT_REACHED(); + } } } -void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, TextDecoration decoration, const SVGTextFragment& fragment, RenderObject* decorationRenderer) +void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, TextDecoration decoration, + const SVGTextFragment& fragment, RenderObject* decorationRenderer, RenderSVGResourceModeFlags resourceMode) { ASSERT(!m_paintingResource); - ASSERT(m_paintingResourceMode != ApplyToDefaultMode); + ASSERT(resourceMode != ApplyToDefaultMode); RenderStyle* decorationStyle = decorationRenderer->style(); ASSERT(decorationStyle); @@ -596,11 +591,12 @@ void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, TextDe float width = fragment.width; const FontMetrics& scaledFontMetrics = scaledFont.fontMetrics(); - GraphicsContextStateSaver stateSaver(*context); + GraphicsContextStateSaver stateSaver(*context, false); if (scalingFactor != 1) { + stateSaver.save(); width *= scalingFactor; decorationOrigin.scale(scalingFactor, scalingFactor); - context->scale(FloatSize(1 / scalingFactor, 1 / scalingFactor)); + context->scale(1 / scalingFactor, 1 / scalingFactor); } decorationOrigin.move(0, -scaledFontMetrics.floatAscent() + positionOffsetForDecoration(decoration, scaledFontMetrics, thickness)); @@ -608,19 +604,22 @@ void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, TextDe Path path; path.addRect(FloatRect(decorationOrigin, FloatSize(width, thickness))); - if (acquirePaintingResource(context, scalingFactor, decorationRenderer, decorationStyle)) - releasePaintingResource(context, &path); + // acquirePaintingResource also modifies state if the scalingFactor is non-identity. + // Above we have saved the state for this case. + if (acquirePaintingResource(context, scalingFactor, decorationRenderer, decorationStyle, resourceMode)) + releasePaintingResource(context, &path, resourceMode); } -void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyle* style, TextRun& textRun, const SVGTextFragment& fragment, int startPosition, int endPosition) +void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyle* style, + TextRun& textRun, const SVGTextFragment& fragment, int startPosition, int endPosition, + RenderSVGResourceModeFlags resourceMode) { - RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); - ASSERT(textRenderer); + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(this->textRenderer()); - float scalingFactor = textRenderer->scalingFactor(); + float scalingFactor = textRenderer.scalingFactor(); ASSERT(scalingFactor); - const Font& scaledFont = textRenderer->scaledFont(); + const Font& scaledFont = textRenderer.scaledFont(); const ShadowList* shadowList = style->textShadow(); // Text shadows are disabled when printing. http://crbug.com/258321 @@ -633,28 +632,28 @@ void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyl textOrigin.scale(scalingFactor, scalingFactor); textSize.scale(scalingFactor); context->save(); - context->scale(FloatSize(1 / scalingFactor, 1 / scalingFactor)); + context->scale(1 / scalingFactor, 1 / scalingFactor); } if (hasShadow) { - DrawLooper drawLooper; + OwnPtr<DrawLooperBuilder> drawLooperBuilder = DrawLooperBuilder::create(); for (size_t i = shadowList->shadows().size(); i--; ) { const ShadowData& shadow = shadowList->shadows()[i]; FloatSize offset(shadow.x(), shadow.y()); - drawLooper.addShadow(offset, shadow.blur(), shadow.color(), - DrawLooper::ShadowRespectsTransforms, DrawLooper::ShadowRespectsAlpha); + drawLooperBuilder->addShadow(offset, shadow.blur(), shadow.color(), + DrawLooperBuilder::ShadowRespectsTransforms, DrawLooperBuilder::ShadowRespectsAlpha); } - drawLooper.addUnmodifiedContent(); - context->setDrawLooper(drawLooper); + drawLooperBuilder->addUnmodifiedContent(); + context->setDrawLooper(drawLooperBuilder.release()); } - if (prepareGraphicsContextForTextPainting(context, scalingFactor, textRun, style)) { + if (prepareGraphicsContextForTextPainting(context, scalingFactor, textRun, style, resourceMode)) { TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.from = startPosition; textRunPaintInfo.to = endPosition; textRunPaintInfo.bounds = FloatRect(textOrigin, textSize); scaledFont.drawText(context, textRunPaintInfo, textOrigin); - restoreGraphicsContextAfterTextPainting(context, textRun); + restoreGraphicsContextAfterTextPainting(context, textRun, resourceMode); } if (scalingFactor != 1) @@ -663,7 +662,9 @@ void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyl context->clearShadow(); } -void SVGInlineTextBox::paintText(GraphicsContext* context, RenderStyle* style, RenderStyle* selectionStyle, const SVGTextFragment& fragment, bool hasSelection, bool paintSelectedTextOnly) +void SVGInlineTextBox::paintText(GraphicsContext* context, RenderStyle* style, + RenderStyle* selectionStyle, const SVGTextFragment& fragment, + RenderSVGResourceModeFlags resourceMode, bool hasSelection, bool paintSelectedTextOnly) { ASSERT(style); ASSERT(selectionStyle); @@ -678,40 +679,104 @@ void SVGInlineTextBox::paintText(GraphicsContext* context, RenderStyle* style, R // Fast path if there is no selection, just draw the whole chunk part using the regular style TextRun textRun = constructTextRun(style, fragment); if (!hasSelection || startPosition >= endPosition) { - paintTextWithShadows(context, style, textRun, fragment, 0, fragment.length); + paintTextWithShadows(context, style, textRun, fragment, 0, fragment.length, resourceMode); return; } // Eventually draw text using regular style until the start position of the selection if (startPosition > 0 && !paintSelectedTextOnly) - paintTextWithShadows(context, style, textRun, fragment, 0, startPosition); + paintTextWithShadows(context, style, textRun, fragment, 0, startPosition, resourceMode); // Draw text using selection style from the start to the end position of the selection - if (style != selectionStyle) - SVGResourcesCache::clientStyleChanged(parent()->renderer(), StyleDifferenceRepaint, selectionStyle); + if (style != selectionStyle) { + StyleDifference diff; + diff.setNeedsRepaintObject(); + SVGResourcesCache::clientStyleChanged(&parent()->renderer(), diff, selectionStyle); + } - TextRun selectionTextRun = constructTextRun(selectionStyle, fragment); - paintTextWithShadows(context, selectionStyle, textRun, fragment, startPosition, endPosition); + paintTextWithShadows(context, selectionStyle, textRun, fragment, startPosition, endPosition, resourceMode); - if (style != selectionStyle) - SVGResourcesCache::clientStyleChanged(parent()->renderer(), StyleDifferenceRepaint, style); + if (style != selectionStyle) { + StyleDifference diff; + diff.setNeedsRepaintObject(); + SVGResourcesCache::clientStyleChanged(&parent()->renderer(), diff, selectionStyle); + } // Eventually draw text using regular style from the end position of the selection to the end of the current chunk part if (endPosition < static_cast<int>(fragment.length) && !paintSelectedTextOnly) - paintTextWithShadows(context, style, textRun, fragment, endPosition, fragment.length); + paintTextWithShadows(context, style, textRun, fragment, endPosition, fragment.length, resourceMode); +} + +void SVGInlineTextBox::paintDocumentMarker(GraphicsContext*, const FloatPoint&, DocumentMarker*, RenderStyle*, const Font&, bool) +{ + // SVG does not have support for generic document markers (e.g., spellchecking, etc). +} + +void SVGInlineTextBox::paintTextMatchMarker(GraphicsContext* context, const FloatPoint&, DocumentMarker* marker, RenderStyle* style, const Font& font) +{ + // SVG is only interested in the TextMatch markers. + if (marker->type() != DocumentMarker::TextMatch) + return; + + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(this->textRenderer()); + + FloatRect markerRect; + AffineTransform fragmentTransform; + for (InlineTextBox* box = textRenderer.firstTextBox(); box; box = box->nextTextBox()) { + if (!box->isSVGInlineTextBox()) + continue; + + SVGInlineTextBox* textBox = toSVGInlineTextBox(box); + + int markerStartPosition = max<int>(marker->startOffset() - textBox->start(), 0); + int markerEndPosition = min<int>(marker->endOffset() - textBox->start(), textBox->len()); + + if (markerStartPosition >= markerEndPosition) + continue; + + const Vector<SVGTextFragment>& fragments = textBox->textFragments(); + unsigned textFragmentsSize = fragments.size(); + for (unsigned i = 0; i < textFragmentsSize; ++i) { + const SVGTextFragment& fragment = fragments.at(i); + + int fragmentStartPosition = markerStartPosition; + int fragmentEndPosition = markerEndPosition; + if (!textBox->mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition)) + continue; + + FloatRect fragmentRect = textBox->selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style); + fragment.buildFragmentTransform(fragmentTransform); + + // Draw the marker highlight. + if (renderer().frame()->editor().markedTextMatchesAreHighlighted()) { + Color color = marker->activeMatch() ? + RenderTheme::theme().platformActiveTextSearchHighlightColor() : + RenderTheme::theme().platformInactiveTextSearchHighlightColor(); + GraphicsContextStateSaver stateSaver(*context); + if (!fragmentTransform.isIdentity()) + context->concatCTM(fragmentTransform); + context->setFillColor(color); + context->fillRect(fragmentRect, color); + } + + fragmentRect = fragmentTransform.mapRect(fragmentRect); + markerRect.unite(fragmentRect); + } + } + + toRenderedDocumentMarker(marker)->setRenderedRect(textRenderer.localToAbsoluteQuad(markerRect).enclosingBoundingBox()); } FloatRect SVGInlineTextBox::calculateBoundaries() const { FloatRect textRect; - RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); - ASSERT(textRenderer); + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(this->textRenderer()); - float scalingFactor = textRenderer->scalingFactor(); + float scalingFactor = textRenderer.scalingFactor(); ASSERT(scalingFactor); - float baseline = textRenderer->scaledFont().fontMetrics().floatAscent() / scalingFactor; + float baseline = textRenderer.scaledFont().fontMetrics().floatAscent() / scalingFactor; AffineTransform fragmentTransform; unsigned textFragmentsSize = m_textFragments.size(); @@ -719,8 +784,7 @@ FloatRect SVGInlineTextBox::calculateBoundaries() const const SVGTextFragment& fragment = m_textFragments.at(i); FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); fragment.buildFragmentTransform(fragmentTransform); - if (!fragmentTransform.isIdentity()) - fragmentRect = fragmentTransform.mapRect(fragmentRect); + fragmentRect = fragmentTransform.mapRect(fragmentRect); textRect.unite(fragmentRect); } @@ -733,18 +797,18 @@ bool SVGInlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& // FIXME: integrate with InlineTextBox::nodeAtPoint better. ASSERT(!isLineBreak()); - PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, request, renderer()->style()->pointerEvents()); - bool isVisible = renderer()->style()->visibility() == VISIBLE; + PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, request, renderer().style()->pointerEvents()); + bool isVisible = renderer().style()->visibility() == VISIBLE; if (isVisible || !hitRules.requireVisible) { if (hitRules.canHitBoundingBox - || (hitRules.canHitStroke && (renderer()->style()->svgStyle()->hasStroke() || !hitRules.requireStroke)) - || (hitRules.canHitFill && (renderer()->style()->svgStyle()->hasFill() || !hitRules.requireFill))) { + || (hitRules.canHitStroke && (renderer().style()->svgStyle()->hasStroke() || !hitRules.requireStroke)) + || (hitRules.canHitFill && (renderer().style()->svgStyle()->hasFill() || !hitRules.requireFill))) { FloatPoint boxOrigin(x(), y()); boxOrigin.moveBy(accumulatedOffset); FloatRect rect(boxOrigin, size()); if (locationInContainer.intersects(rect)) { - renderer()->updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); - if (!result.addNodeToRectBasedTestResult(renderer()->node(), request, locationInContainer, rect)) + renderer().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); + if (!result.addNodeToRectBasedTestResult(renderer().node(), request, locationInContainer, rect)) return true; } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineTextBox.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineTextBox.h index ccec860b863..2a5cb1bcd0e 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineTextBox.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineTextBox.h @@ -23,38 +23,38 @@ #define SVGInlineTextBox_h #include "core/rendering/InlineTextBox.h" +#include "core/rendering/svg/RenderSVGResource.h" #include "core/rendering/svg/SVGTextLayoutEngine.h" namespace WebCore { class RenderSVGResource; -class SVGRootInlineBox; class SVGInlineTextBox FINAL : public InlineTextBox { public: - SVGInlineTextBox(RenderObject*); + SVGInlineTextBox(RenderObject&); - virtual bool isSVGInlineTextBox() const { return true; } + virtual bool isSVGInlineTextBox() const OVERRIDE { return true; } - virtual float virtualLogicalHeight() const { return m_logicalHeight; } + virtual float virtualLogicalHeight() const OVERRIDE { return m_logicalHeight; } void setLogicalHeight(float height) { m_logicalHeight = height; } - virtual int offsetForPosition(float x, bool includePartialGlyphs = true) const; - virtual float positionForOffset(int offset) const; + virtual int offsetForPosition(float x, bool includePartialGlyphs = true) const OVERRIDE; + virtual float positionForOffset(int offset) const OVERRIDE; void paintSelectionBackground(PaintInfo&); - virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); - virtual LayoutRect localSelectionRect(int startPosition, int endPosition); + virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; + virtual LayoutRect localSelectionRect(int startPosition, int endPosition) OVERRIDE; bool mapStartEndPositionsIntoFragmentCoordinates(const SVGTextFragment&, int& startPosition, int& endPosition) const; - virtual FloatRect calculateBoundaries() const; + virtual FloatRect calculateBoundaries() const OVERRIDE; void clearTextFragments() { m_textFragments.clear(); } Vector<SVGTextFragment>& textFragments() { return m_textFragments; } const Vector<SVGTextFragment>& textFragments() const { return m_textFragments; } - virtual void dirtyLineBoxes() OVERRIDE FINAL; + virtual void dirtyLineBoxes() OVERRIDE; bool startsNewTextChunk() const { return m_startsNewTextChunk; } void setStartsNewTextChunk(bool newTextChunk) { m_startsNewTextChunk = newTextChunk; } @@ -65,23 +65,30 @@ public: private: TextRun constructTextRun(RenderStyle*, const SVGTextFragment&) const; - bool acquirePaintingResource(GraphicsContext*&, float scalingFactor, RenderObject*, RenderStyle*); - void releasePaintingResource(GraphicsContext*&, const Path*); + bool acquirePaintingResource(GraphicsContext*&, float scalingFactor, RenderObject*, + RenderStyle*, RenderSVGResourceModeFlags); + void releasePaintingResource(GraphicsContext*&, const Path*, RenderSVGResourceModeFlags); - bool prepareGraphicsContextForTextPainting(GraphicsContext*&, float scalingFactor, TextRun&, RenderStyle*); - void restoreGraphicsContextAfterTextPainting(GraphicsContext*&, TextRun&); + bool prepareGraphicsContextForTextPainting(GraphicsContext*&, float scalingFactor, TextRun&, + RenderStyle*, RenderSVGResourceModeFlags); + void restoreGraphicsContextAfterTextPainting(GraphicsContext*&, TextRun&, RenderSVGResourceModeFlags); void paintDecoration(GraphicsContext*, TextDecoration, const SVGTextFragment&); - void paintDecorationWithStyle(GraphicsContext*, TextDecoration, const SVGTextFragment&, RenderObject* decorationRenderer); - void paintTextWithShadows(GraphicsContext*, RenderStyle*, TextRun&, const SVGTextFragment&, int startPosition, int endPosition); - void paintText(GraphicsContext*, RenderStyle*, RenderStyle* selectionStyle, const SVGTextFragment&, bool hasSelection, bool paintSelectedTextOnly); + void paintDecorationWithStyle(GraphicsContext*, TextDecoration, const SVGTextFragment&, + RenderObject* decorationRenderer, RenderSVGResourceModeFlags); + void paintTextWithShadows(GraphicsContext*, RenderStyle*, TextRun&, const SVGTextFragment&, + int startPosition, int endPosition, RenderSVGResourceModeFlags); + void paintText(GraphicsContext*, RenderStyle*, RenderStyle* selectionStyle, const SVGTextFragment&, + RenderSVGResourceModeFlags, bool hasSelection, bool paintSelectedTextOnly); + + virtual void paintDocumentMarker(GraphicsContext*, const FloatPoint&, DocumentMarker*, RenderStyle*, const Font&, bool) OVERRIDE FINAL; + virtual void paintTextMatchMarker(GraphicsContext*, const FloatPoint&, DocumentMarker*, RenderStyle*, const Font&) OVERRIDE FINAL; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; private: float m_logicalHeight; - unsigned m_paintingResourceMode : 4; - unsigned m_startsNewTextChunk : 1; + bool m_startsNewTextChunk : 1; RenderSVGResource* m_paintingResource; Vector<SVGTextFragment> m_textFragments; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGMarkerData.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGMarkerData.h index aebd83b3e1a..1b31b98b87f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGMarkerData.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGMarkerData.h @@ -26,8 +26,6 @@ namespace WebCore { -class RenderSVGResourceMarker; - enum SVGMarkerType { StartMarker, MidMarker, diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGPathData.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGPathData.cpp index f42f6410e57..5a18ba50295 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGPathData.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGPathData.cpp @@ -20,7 +20,7 @@ #include "config.h" #include "core/rendering/svg/SVGPathData.h" -#include "SVGNames.h" +#include "core/SVGNames.h" #include "core/svg/SVGCircleElement.h" #include "core/svg/SVGEllipseElement.h" #include "core/svg/SVGLineElement.h" @@ -34,14 +34,16 @@ namespace WebCore { +using namespace SVGNames; + static void updatePathFromCircleElement(SVGElement* element, Path& path) { SVGCircleElement* circle = toSVGCircleElement(element); SVGLengthContext lengthContext(element); - float r = circle->rCurrentValue().value(lengthContext); + float r = circle->r()->currentValue()->value(lengthContext); if (r > 0) - path.addEllipse(FloatRect(circle->cxCurrentValue().value(lengthContext) - r, circle->cyCurrentValue().value(lengthContext) - r, r * 2, r * 2)); + path.addEllipse(FloatRect(circle->cx()->currentValue()->value(lengthContext) - r, circle->cy()->currentValue()->value(lengthContext) - r, r * 2, r * 2)); } static void updatePathFromEllipseElement(SVGElement* element, Path& path) @@ -49,13 +51,16 @@ static void updatePathFromEllipseElement(SVGElement* element, Path& path) SVGEllipseElement* ellipse = toSVGEllipseElement(element); SVGLengthContext lengthContext(element); - float rx = ellipse->rxCurrentValue().value(lengthContext); - if (rx <= 0) + float rx = ellipse->rx()->currentValue()->value(lengthContext); + if (rx < 0) + return; + float ry = ellipse->ry()->currentValue()->value(lengthContext); + if (ry < 0) return; - float ry = ellipse->ryCurrentValue().value(lengthContext); - if (ry <= 0) + if (!rx && !ry) return; - path.addEllipse(FloatRect(ellipse->cxCurrentValue().value(lengthContext) - rx, ellipse->cyCurrentValue().value(lengthContext) - ry, rx * 2, ry * 2)); + + path.addEllipse(FloatRect(ellipse->cx()->currentValue()->value(lengthContext) - rx, ellipse->cy()->currentValue()->value(lengthContext) - ry, rx * 2, ry * 2)); } static void updatePathFromLineElement(SVGElement* element, Path& path) @@ -63,8 +68,8 @@ static void updatePathFromLineElement(SVGElement* element, Path& path) SVGLineElement* line = toSVGLineElement(element); SVGLengthContext lengthContext(element); - path.moveTo(FloatPoint(line->x1CurrentValue().value(lengthContext), line->y1CurrentValue().value(lengthContext))); - path.addLineTo(FloatPoint(line->x2CurrentValue().value(lengthContext), line->y2CurrentValue().value(lengthContext))); + path.moveTo(FloatPoint(line->x1()->currentValue()->value(lengthContext), line->y1()->currentValue()->value(lengthContext))); + path.addLineTo(FloatPoint(line->x2()->currentValue()->value(lengthContext), line->y2()->currentValue()->value(lengthContext))); } static void updatePathFromPathElement(SVGElement* element, Path& path) @@ -72,32 +77,26 @@ static void updatePathFromPathElement(SVGElement* element, Path& path) buildPathFromByteStream(toSVGPathElement(element)->pathByteStream(), path); } -static void updatePathFromPolygonElement(SVGElement* element, Path& path) +static void updatePathFromPolylineElement(SVGElement* element, Path& path) { - SVGPointList& points = toSVGPolygonElement(element)->pointsCurrentValue(); - if (points.isEmpty()) + RefPtr<SVGPointList> points = toSVGPolyElement(element)->points()->currentValue(); + if (points->isEmpty()) return; - path.moveTo(points.first()); - - unsigned size = points.size(); - for (unsigned i = 1; i < size; ++i) - path.addLineTo(points.at(i)); + SVGPointList::ConstIterator it = points->begin(); + SVGPointList::ConstIterator itEnd = points->end(); + ASSERT(it != itEnd); + path.moveTo(it->value()); + ++it; - path.closeSubpath(); + for (; it != itEnd; ++it) + path.addLineTo(it->value()); } -static void updatePathFromPolylineElement(SVGElement* element, Path& path) +static void updatePathFromPolygonElement(SVGElement* element, Path& path) { - SVGPointList& points = toSVGPolylineElement(element)->pointsCurrentValue(); - if (points.isEmpty()) - return; - - path.moveTo(points.first()); - - unsigned size = points.size(); - for (unsigned i = 1; i < size; ++i) - path.addLineTo(points.at(i)); + updatePathFromPolylineElement(element, path); + path.closeSubpath(); } static void updatePathFromRectElement(SVGElement* element, Path& path) @@ -105,19 +104,21 @@ static void updatePathFromRectElement(SVGElement* element, Path& path) SVGRectElement* rect = toSVGRectElement(element); SVGLengthContext lengthContext(element); - float width = rect->widthCurrentValue().value(lengthContext); - if (width <= 0) + float width = rect->width()->currentValue()->value(lengthContext); + if (width < 0) + return; + float height = rect->height()->currentValue()->value(lengthContext); + if (height < 0) return; - float height = rect->heightCurrentValue().value(lengthContext); - if (height <= 0) + if (!width && !height) return; - float x = rect->xCurrentValue().value(lengthContext); - float y = rect->yCurrentValue().value(lengthContext); - bool hasRx = rect->rxCurrentValue().value(lengthContext) > 0; - bool hasRy = rect->ryCurrentValue().value(lengthContext) > 0; + float x = rect->x()->currentValue()->value(lengthContext); + float y = rect->y()->currentValue()->value(lengthContext); + float rx = rect->rx()->currentValue()->value(lengthContext); + float ry = rect->ry()->currentValue()->value(lengthContext); + bool hasRx = rx > 0; + bool hasRy = ry > 0; if (hasRx || hasRy) { - float rx = rect->rxCurrentValue().value(lengthContext); - float ry = rect->ryCurrentValue().value(lengthContext); if (!hasRx) rx = ry; else if (!hasRy) @@ -139,13 +140,13 @@ void updatePathFromGraphicsElement(SVGElement* element, Path& path) static HashMap<StringImpl*, PathUpdateFunction>* map = 0; if (!map) { map = new HashMap<StringImpl*, PathUpdateFunction>; - map->set(SVGNames::circleTag.localName().impl(), updatePathFromCircleElement); - map->set(SVGNames::ellipseTag.localName().impl(), updatePathFromEllipseElement); - map->set(SVGNames::lineTag.localName().impl(), updatePathFromLineElement); - map->set(SVGNames::pathTag.localName().impl(), updatePathFromPathElement); - map->set(SVGNames::polygonTag.localName().impl(), updatePathFromPolygonElement); - map->set(SVGNames::polylineTag.localName().impl(), updatePathFromPolylineElement); - map->set(SVGNames::rectTag.localName().impl(), updatePathFromRectElement); + map->set(circleTag.localName().impl(), updatePathFromCircleElement); + map->set(ellipseTag.localName().impl(), updatePathFromEllipseElement); + map->set(lineTag.localName().impl(), updatePathFromLineElement); + map->set(pathTag.localName().impl(), updatePathFromPathElement); + map->set(polygonTag.localName().impl(), updatePathFromPolygonElement); + map->set(polylineTag.localName().impl(), updatePathFromPolylineElement); + map->set(rectTag.localName().impl(), updatePathFromRectElement); } if (PathUpdateFunction pathUpdateFunction = map->get(element->localName().impl())) diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderSupport.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderSupport.cpp index cfc4a641f7f..56c9e2cffdd 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderSupport.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderSupport.cpp @@ -23,9 +23,9 @@ */ #include "config.h" - #include "core/rendering/svg/SVGRenderSupport.h" +#include "core/rendering/PaintInfo.h" #include "core/rendering/RenderGeometryMap.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/SubtreeLayoutScope.h" @@ -51,8 +51,8 @@ LayoutRect SVGRenderSupport::clippedOverflowRectForRepaint(const RenderObject* o // Pass our local paint rect to computeRectForRepaint() which will // map to parent coords and recurse up the parent chain. - FloatRect repaintRect = object->repaintRectInLocalCoordinates(); - object->computeFloatRectForRepaint(repaintContainer, repaintRect); + FloatRect repaintRect = object->paintInvalidationRectInLocalCoordinates(); + object->computeFloatRectForPaintInvalidation(repaintContainer, repaintRect); return enclosingLayoutRect(repaintRect); } @@ -60,9 +60,9 @@ void SVGRenderSupport::computeFloatRectForRepaint(const RenderObject* object, co { repaintRect.inflate(object->style()->outlineWidth()); - // Translate to coords in our parent renderer, and then call computeFloatRectForRepaint() on our parent. + // Translate to coords in our parent renderer, and then call computeFloatRectForPaintInvalidation() on our parent. repaintRect = object->localToParentTransform().mapRect(repaintRect); - object->parent()->computeFloatRectForRepaint(repaintContainer, repaintRect, fixed); + object->parent()->computeFloatRectForPaintInvalidation(repaintContainer, repaintRect, fixed); } void SVGRenderSupport::mapLocalToContainer(const RenderObject* object, const RenderLayerModelObject* repaintContainer, TransformState& transformState, bool* wasFixed) @@ -100,18 +100,24 @@ const RenderObject* SVGRenderSupport::pushMappingToContainer(const RenderObject* return parent; } -bool SVGRenderSupport::checkForSVGRepaintDuringLayout(RenderObject* object) +bool SVGRenderSupport::parentTransformDidChange(RenderObject* object) { - if (!object->checkForRepaintDuringLayout()) - return false; // When a parent container is transformed in SVG, all children will be painted automatically // so we are able to skip redundant repaint checks. RenderObject* parent = object->parent(); return !(parent && parent->isSVGContainer() && toRenderSVGContainer(parent)->didTransformToRootUpdate()); } +bool SVGRenderSupport::checkForSVGRepaintDuringLayout(RenderObject* object) +{ + if (!object->checkForPaintInvalidationDuringLayout()) + return false; + + return parentTransformDidChange(object); +} + // 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) +inline void SVGRenderSupport::updateObjectBoundingBox(FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, RenderObject* other, FloatRect otherBoundingBox) { bool otherValid = other->isSVGContainer() ? toRenderSVGContainer(other)->isObjectBoundingBoxValid() : true; if (!otherValid) @@ -135,18 +141,14 @@ void SVGRenderSupport::computeContainerBoundingBoxes(const RenderObject* contain // When computing the strokeBoundingBox, we use the repaintRects of the container's children so that the container's stroke includes // the resources applied to the children (such as clips and filters). This allows filters applied to containers to correctly bound // the children, and also improves inlining of SVG content, as the stroke bound is used in that situation also. - for (RenderObject* current = container->firstChild(); current; current = current->nextSibling()) { + for (RenderObject* current = container->slowFirstChild(); current; current = current->nextSibling()) { if (current->isSVGHiddenContainer()) continue; const AffineTransform& transform = current->localToParentTransform(); - if (transform.isIdentity()) { - updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, current, current->objectBoundingBox()); - strokeBoundingBox.unite(current->repaintRectInLocalCoordinates()); - } else { - updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, current, transform.mapRect(current->objectBoundingBox())); - strokeBoundingBox.unite(transform.mapRect(current->repaintRectInLocalCoordinates())); - } + updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, current, + transform.mapRect(current->objectBoundingBox())); + strokeBoundingBox.unite(transform.mapRect(current->paintInvalidationRectInLocalCoordinates())); } repaintBoundingBox = strokeBoundingBox; @@ -154,9 +156,6 @@ void SVGRenderSupport::computeContainerBoundingBoxes(const RenderObject* contain bool SVGRenderSupport::paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo& paintInfo) { - if (localTransform.isIdentity()) - return localRepaintRect.intersects(paintInfo.rect); - return localTransform.mapRect(localRepaintRect).intersects(paintInfo.rect); } @@ -170,17 +169,17 @@ const RenderSVGRoot* SVGRenderSupport::findTreeRootObject(const RenderObject* st return toRenderSVGRoot(start); } -static inline void invalidateResourcesOfChildren(RenderObject* start) +inline void SVGRenderSupport::invalidateResourcesOfChildren(RenderObject* start) { ASSERT(!start->needsLayout()); if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(start)) resources->removeClientFromCache(start, false); - for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) + for (RenderObject* child = start->slowFirstChild(); child; child = child->nextSibling()) invalidateResourcesOfChildren(child); } -static inline bool layoutSizeOfNearestViewportChanged(const RenderObject* start) +inline bool SVGRenderSupport::layoutSizeOfNearestViewportChanged(const RenderObject* start) { while (start && !start->isSVGRoot() && !start->isSVGViewportContainer()) start = start->parent(); @@ -212,7 +211,7 @@ void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout) bool transformChanged = transformToRootChanged(start); HashSet<RenderObject*> notlayoutedObjects; - for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { + for (RenderObject* child = start->slowFirstChild(); child; child = child->nextSibling()) { bool needsLayout = selfNeedsLayout; bool childEverHadLayout = child->everHadLayout(); @@ -228,9 +227,9 @@ void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout) if (SVGElement* element = child->node()->isSVGElement() ? toSVGElement(child->node()) : 0) { if (element->hasRelativeLengths()) { // When the layout size changed and when using relative values tell the RenderSVGShape to update its shape object - if (child->isSVGShape()) + if (child->isSVGShape()) { toRenderSVGShape(child)->setNeedsShapeUpdate(); - else if (child->isSVGText()) { + } else if (child->isSVGText()) { toRenderSVGText(child)->setNeedsTextMetricsUpdate(); toRenderSVGText(child)->setNeedsPositioningValuesUpdate(); } @@ -240,7 +239,7 @@ void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout) } } - SubtreeLayoutScope layoutScope(child); + SubtreeLayoutScope layoutScope(*child); // Resource containers are nasty: they can invalidate clients outside the current SubtreeLayoutScope. // Since they only care about viewport size changes (to resolve their relative lengths), we trigger // their invalidation directly from SVGSVGElement::svgAttributeChange() or at a higher @@ -257,9 +256,10 @@ void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout) // We could handle this in the individual objects, but for now it's easier to have // parent containers call repaint(). (RenderBlock::layout* has similar logic.) if (!childEverHadLayout && !RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) - child->repaint(); - } else if (layoutSizeChanged) + child->paintInvalidationForWholeRenderer(); + } else if (layoutSizeChanged) { notlayoutedObjects.add(child); + } } if (!layoutSizeChanged) { @@ -284,23 +284,16 @@ void SVGRenderSupport::layoutResourcesIfNeeded(const RenderObject* object) 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 StyleResolver::adjustRenderStyle - ASSERT(object->style()->overflowX() != OSCROLL); - // RenderSVGRoot should never query for overflow state - it should always clip itself to the initial viewport size. - ASSERT(!object->isRoot()); + ASSERT(!object->isDocumentElement()); - return object->style()->overflowX() == OHIDDEN; + return object->style()->overflowX() == OHIDDEN || object->style()->overflowX() == OSCROLL; } -void SVGRenderSupport::intersectRepaintRectWithResources(const RenderObject* object, FloatRect& repaintRect) +void SVGRenderSupport::intersectRepaintRectWithResources(const RenderObject* renderer, FloatRect& repaintRect) { - ASSERT(object); + ASSERT(renderer); - RenderObject* renderer = const_cast<RenderObject*>(object); SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer); if (!resources) return; @@ -357,21 +350,22 @@ void SVGRenderSupport::applyStrokeStyleToContext(GraphicsContext* context, const ASSERT(svgStyle); SVGLengthContext lengthContext(toSVGElement(object->node())); - context->setStrokeThickness(svgStyle->strokeWidth().value(lengthContext)); + context->setStrokeThickness(svgStyle->strokeWidth()->value(lengthContext)); context->setLineCap(svgStyle->capStyle()); context->setLineJoin(svgStyle->joinStyle()); context->setMiterLimit(svgStyle->strokeMiterLimit()); - const Vector<SVGLength>& dashes = svgStyle->strokeDashArray(); - if (dashes.isEmpty()) + RefPtr<SVGLengthList> dashes = svgStyle->strokeDashArray(); + if (dashes->isEmpty()) return; DashArray dashArray; - const Vector<SVGLength>::const_iterator end = dashes.end(); - for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it) - dashArray.append((*it).value(lengthContext)); + SVGLengthList::ConstIterator it = dashes->begin(); + SVGLengthList::ConstIterator itEnd = dashes->end(); + for (; it != itEnd; ++it) + dashArray.append(it->value(lengthContext)); - context->setLineDash(dashArray, svgStyle->strokeDashOffset().value(lengthContext)); + context->setLineDash(dashArray, svgStyle->strokeDashOffset()->value(lengthContext)); } void SVGRenderSupport::applyStrokeStyleToStrokeData(StrokeData* strokeData, const RenderStyle* style, const RenderObject* object) @@ -386,29 +380,28 @@ void SVGRenderSupport::applyStrokeStyleToStrokeData(StrokeData* strokeData, cons ASSERT(svgStyle); SVGLengthContext lengthContext(toSVGElement(object->node())); - strokeData->setThickness(svgStyle->strokeWidth().value(lengthContext)); + strokeData->setThickness(svgStyle->strokeWidth()->value(lengthContext)); strokeData->setLineCap(svgStyle->capStyle()); strokeData->setLineJoin(svgStyle->joinStyle()); strokeData->setMiterLimit(svgStyle->strokeMiterLimit()); - const Vector<SVGLength>& dashes = svgStyle->strokeDashArray(); - if (dashes.isEmpty()) + RefPtr<SVGLengthList> dashes = svgStyle->strokeDashArray(); + if (dashes->isEmpty()) return; DashArray dashArray; - const Vector<SVGLength>::const_iterator end = dashes.end(); - for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it) - dashArray.append((*it).value(lengthContext)); + size_t length = dashes->length(); + for (size_t i = 0; i < length; ++i) + dashArray.append(dashes->at(i)->value(lengthContext)); - strokeData->setLineDash(dashArray, svgStyle->strokeDashOffset().value(lengthContext)); + strokeData->setLineDash(dashArray, svgStyle->strokeDashOffset()->value(lengthContext)); } -bool SVGRenderSupport::isEmptySVGInlineText(const RenderObject* object) +bool SVGRenderSupport::isRenderableTextNode(const RenderObject* object) { - // RenderSVGInlineText performs whitespace filtering in order to support xml:space - // (http://www.w3.org/TR/SVG/struct.html#LangSpaceAttrs), and can end up with an empty string - // even when its original constructor argument is non-empty. - return object->isSVGInlineText() && toRenderSVGInlineText(object)->hasEmptyText(); + ASSERT(object->isText()); + // <br> is marked as text, but is not handled by the SVG rendering code-path. + return object->isSVGInlineText() && !toRenderSVGInlineText(object)->hasEmptyText(); } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderSupport.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderSupport.h index 4265f64c780..087dcfbbd44 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderSupport.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderSupport.h @@ -24,23 +24,22 @@ #ifndef SVGRenderSupport_h #define SVGRenderSupport_h -#include "core/rendering/PaintInfo.h" - namespace WebCore { +class AffineTransform; class FloatPoint; class FloatRect; -class ImageBuffer; +class GraphicsContext; class LayoutRect; -class RenderBoxModelObject; +struct PaintInfo; class RenderGeometryMap; class RenderLayerModelObject; class RenderObject; class RenderStyle; class RenderSVGRoot; +class StrokeData; class TransformState; -// SVGRendererSupport is a helper class sharing code between all SVG renderers. class SVGRenderSupport { public: // Shares child layouting code between RenderSVGRoot/RenderSVG(Hidden)Container @@ -62,8 +61,11 @@ public: static bool pointInClippingArea(RenderObject*, const FloatPoint&); 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&); + static bool parentTransformDidChange(RenderObject*); + // Important functions used by nearly all SVG renderers centralizing coordinate transformations / repaint rect calculations static LayoutRect clippedOverflowRectForRepaint(const RenderObject*, const RenderLayerModelObject* repaintContainer); static void computeFloatRectForRepaint(const RenderObject*, const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed); @@ -81,13 +83,14 @@ public: // FIXME: These methods do not belong here. static const RenderSVGRoot* findTreeRootObject(const RenderObject*); - // Helper method for determining whether an RenderSVGInlineText object has zero length text. - static bool isEmptySVGInlineText(const RenderObject*); + // Helper method for determining if a RenderObject marked as text (isText()== true) + // can/will be rendered as part of a <text>. + static bool isRenderableTextNode(const RenderObject*); private: - // This class is not constructable. - SVGRenderSupport(); - ~SVGRenderSupport(); + static void updateObjectBoundingBox(FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, RenderObject* other, FloatRect otherBoundingBox); + static void invalidateResourcesOfChildren(RenderObject* start); + static bool layoutSizeOfNearestViewportChanged(const RenderObject* start); }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderTreeAsText.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderTreeAsText.cpp index b92e9b99833..15726cb9c37 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderTreeAsText.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderTreeAsText.cpp @@ -30,7 +30,6 @@ #include "core/rendering/svg/SVGRenderTreeAsText.h" -#include "SVGNames.h" #include "core/rendering/InlineTextBox.h" #include "core/rendering/RenderTreeAsText.h" #include "core/rendering/svg/RenderSVGGradientStop.h" @@ -64,6 +63,7 @@ #include "core/svg/SVGRadialGradientElement.h" #include "core/svg/SVGRectElement.h" #include "core/svg/SVGStopElement.h" +#include "platform/graphics/DashArray.h" #include "platform/graphics/GraphicsTypes.h" #include <math.h> @@ -154,15 +154,35 @@ static TextStream& operator<<(TextStream& ts, const WindRule rule) return ts; } +namespace { + +template<typename Enum> +String SVGEnumerationToString(Enum value) +{ + const SVGEnumerationStringEntries& entries = getStaticStringEntries<Enum>(); + + SVGEnumerationStringEntries::const_iterator it = entries.begin(); + SVGEnumerationStringEntries::const_iterator itEnd = entries.end(); + for (; it != itEnd; ++it) { + if (value == it->first) + return it->second; + } + + ASSERT_NOT_REACHED(); + return String(); +} + +} + static TextStream& operator<<(TextStream& ts, const SVGUnitTypes::SVGUnitType& unitType) { - ts << SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::toString(unitType); + ts << SVGEnumerationToString<SVGUnitTypes::SVGUnitType>(unitType); return ts; } static TextStream& operator<<(TextStream& ts, const SVGMarkerUnitsType& markerUnit) { - ts << SVGPropertyTraits<SVGMarkerUnitsType>::toString(markerUnit); + ts << SVGEnumerationToString<SVGMarkerUnitsType>(markerUnit); return ts; } @@ -221,7 +241,7 @@ static TextStream& operator<<(TextStream& ts, LineJoin style) static TextStream& operator<<(TextStream& ts, const SVGSpreadMethodType& type) { - ts << SVGPropertyTraits<SVGSpreadMethodType>::toString(type).upper(); + ts << SVGEnumerationToString<SVGSpreadMethodType>(type).upper(); return ts; } @@ -260,21 +280,22 @@ static void writeStyle(TextStream& ts, const RenderObject& object) const RenderSVGShape& shape = static_cast<const RenderSVGShape&>(object); ASSERT(shape.element()); - Color fallbackColor; - if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(const_cast<RenderSVGShape*>(&shape), shape.style(), fallbackColor)) { + bool hasFallback; + if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(const_cast<RenderSVGShape*>(&shape), shape.style(), hasFallback)) { TextStreamSeparator s(" "); ts << " [stroke={" << s; writeSVGPaintingResource(ts, strokePaintingResource); SVGLengthContext lengthContext(shape.element()); - double dashOffset = svgStyle->strokeDashOffset().value(lengthContext); - double strokeWidth = svgStyle->strokeWidth().value(lengthContext); - const Vector<SVGLength>& dashes = svgStyle->strokeDashArray(); + double dashOffset = svgStyle->strokeDashOffset()->value(lengthContext); + double strokeWidth = svgStyle->strokeWidth()->value(lengthContext); + RefPtr<SVGLengthList> dashes = svgStyle->strokeDashArray(); DashArray dashArray; - const Vector<SVGLength>::const_iterator end = dashes.end(); - for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it) - dashArray.append((*it).value(lengthContext)); + SVGLengthList::ConstIterator it = dashes->begin(); + SVGLengthList::ConstIterator itEnd = dashes->end(); + for (; it != itEnd; ++it) + dashArray.append(it->value(lengthContext)); writeIfNotDefault(ts, "opacity", svgStyle->strokeOpacity(), 1.0f); writeIfNotDefault(ts, "stroke width", strokeWidth, 1.0); @@ -288,7 +309,7 @@ static void writeStyle(TextStream& ts, const RenderObject& object) ts << "}]"; } - if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(const_cast<RenderSVGShape*>(&shape), shape.style(), fallbackColor)) { + if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(const_cast<RenderSVGShape*>(&shape), shape.style(), hasFallback)) { TextStreamSeparator s(" "); ts << " [fill={" << s; writeSVGPaintingResource(ts, fillPaintingResource); @@ -317,37 +338,38 @@ static TextStream& operator<<(TextStream& ts, const RenderSVGShape& shape) writePositionAndStyle(ts, shape); SVGElement* svgElement = shape.element(); + ASSERT(svgElement); SVGLengthContext lengthContext(svgElement); - if (svgElement->hasTagName(SVGNames::rectTag)) { - SVGRectElement* element = toSVGRectElement(svgElement); - writeNameValuePair(ts, "x", element->xCurrentValue().value(lengthContext)); - writeNameValuePair(ts, "y", element->yCurrentValue().value(lengthContext)); - writeNameValuePair(ts, "width", element->widthCurrentValue().value(lengthContext)); - writeNameValuePair(ts, "height", element->heightCurrentValue().value(lengthContext)); - } else if (svgElement->hasTagName(SVGNames::lineTag)) { - SVGLineElement* element = toSVGLineElement(svgElement); - writeNameValuePair(ts, "x1", element->x1CurrentValue().value(lengthContext)); - writeNameValuePair(ts, "y1", element->y1CurrentValue().value(lengthContext)); - writeNameValuePair(ts, "x2", element->x2CurrentValue().value(lengthContext)); - writeNameValuePair(ts, "y2", element->y2CurrentValue().value(lengthContext)); - } else if (svgElement->hasTagName(SVGNames::ellipseTag)) { - SVGEllipseElement* element = toSVGEllipseElement(svgElement); - writeNameValuePair(ts, "cx", element->cxCurrentValue().value(lengthContext)); - writeNameValuePair(ts, "cy", element->cyCurrentValue().value(lengthContext)); - writeNameValuePair(ts, "rx", element->rxCurrentValue().value(lengthContext)); - writeNameValuePair(ts, "ry", element->ryCurrentValue().value(lengthContext)); - } else if (svgElement->hasTagName(SVGNames::circleTag)) { - SVGCircleElement* element = toSVGCircleElement(svgElement); - writeNameValuePair(ts, "cx", element->cxCurrentValue().value(lengthContext)); - writeNameValuePair(ts, "cy", element->cyCurrentValue().value(lengthContext)); - writeNameValuePair(ts, "r", element->rCurrentValue().value(lengthContext)); - } else if (svgElement->hasTagName(SVGNames::polygonTag) || svgElement->hasTagName(SVGNames::polylineTag)) { - writeNameAndQuotedValue(ts, "points", toSVGPolyElement(svgElement)->pointsCurrentValue().valueAsString()); - } else if (svgElement->hasTagName(SVGNames::pathTag)) { + if (isSVGRectElement(*svgElement)) { + SVGRectElement& element = toSVGRectElement(*svgElement); + writeNameValuePair(ts, "x", element.x()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "y", element.y()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "width", element.width()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "height", element.height()->currentValue()->value(lengthContext)); + } else if (isSVGLineElement(*svgElement)) { + SVGLineElement& element = toSVGLineElement(*svgElement); + writeNameValuePair(ts, "x1", element.x1()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "y1", element.y1()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "x2", element.x2()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "y2", element.y2()->currentValue()->value(lengthContext)); + } else if (isSVGEllipseElement(*svgElement)) { + SVGEllipseElement& element = toSVGEllipseElement(*svgElement); + writeNameValuePair(ts, "cx", element.cx()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "cy", element.cy()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "rx", element.rx()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "ry", element.ry()->currentValue()->value(lengthContext)); + } else if (isSVGCircleElement(*svgElement)) { + SVGCircleElement& element = toSVGCircleElement(*svgElement); + writeNameValuePair(ts, "cx", element.cx()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "cy", element.cy()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "r", element.r()->currentValue()->value(lengthContext)); + } else if (isSVGPolyElement(*svgElement)) { + writeNameAndQuotedValue(ts, "points", toSVGPolyElement(*svgElement).points()->currentValue()->valueAsString()); + } else if (isSVGPathElement(*svgElement)) { String pathString; // FIXME: We should switch to UnalteredParsing here - this will affect the path dumping output of dozens of tests. - buildStringFromByteStream(toSVGPathElement(svgElement)->pathByteStream(), pathString, NormalizedParsing); + buildStringFromByteStream(toSVGPathElement(*svgElement).pathByteStream(), pathString, NormalizedParsing); writeNameAndQuotedValue(ts, "data", pathString); } else ASSERT_NOT_REACHED(); @@ -380,11 +402,10 @@ static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textB if (fragments.isEmpty()) return; - RenderSVGInlineText* textRenderer = toRenderSVGInlineText(textBox->textRenderer()); - ASSERT(textRenderer); + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(textBox->textRenderer()); - const SVGRenderStyle* svgStyle = textRenderer->style()->svgStyle(); - String text = textBox->textRenderer()->text(); + const SVGRenderStyle* svgStyle = textRenderer.style()->svgStyle(); + String text = textBox->textRenderer().text(); unsigned fragmentsSize = fragments.size(); for (unsigned i = 0; i < fragmentsSize; ++i) { @@ -452,7 +473,7 @@ static void writeStandardPrefix(TextStream& ts, const RenderObject& object, int static void writeChildren(TextStream& ts, const RenderObject& object, int indent) { - for (RenderObject* child = object.firstChild(); child; child = child->nextSibling()) + for (RenderObject* child = object.slowFirstChild(); child; child = child->nextSibling()) write(ts, *child, indent + 1); } @@ -490,7 +511,8 @@ void writeSVGResourceContainer(TextStream& ts, const RenderObject& object, int i ts << "\n"; // Creating a placeholder filter which is passed to the builder. FloatRect dummyRect; - RefPtr<SVGFilter> dummyFilter = SVGFilter::create(AffineTransform(), dummyRect, dummyRect, dummyRect, true); + IntRect dummyIntRect; + RefPtr<SVGFilter> dummyFilter = SVGFilter::create(AffineTransform(), dummyIntRect, dummyRect, dummyRect, true); if (RefPtr<SVGFilterBuilder> builder = filter->buildPrimitives(dummyFilter.get())) { if (FilterEffect* lastEffect = builder->lastEffect()) lastEffect->externalRepresentation(ts, indent + 1); @@ -614,7 +636,7 @@ void writeSVGGradientStop(TextStream& ts, const RenderSVGGradientStop& stop, int if (!style) return; - ts << " [offset=" << stopElement->offsetCurrentValue() << "] [color=" << stopElement->stopColorIncludingOpacity() << "]\n"; + ts << " [offset=" << stopElement->offset()->currentValue()->value() << "] [color=" << stopElement->stopColorIncludingOpacity() << "]\n"; } void writeResources(TextStream& ts, const RenderObject& object, int indent) diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderTreeAsText.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderTreeAsText.h index 055c587df57..63f26442a6d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderTreeAsText.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderTreeAsText.h @@ -31,10 +31,6 @@ namespace WebCore { class Color; -class FloatRect; -class FloatSize; -class Node; -class RenderImage; class RenderObject; class RenderSVGGradientStop; class RenderSVGImage; @@ -43,7 +39,6 @@ class RenderSVGShape; class RenderSVGRoot; class RenderSVGText; class AffineTransform; -class SVGUnitTypes; // functions used by the main RenderTreeAsText code void write(TextStream&, const RenderSVGShape&, int indent); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderingContext.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderingContext.cpp index 55545097c0f..23766e3a505 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderingContext.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderingContext.cpp @@ -26,9 +26,10 @@ #include "core/rendering/svg/SVGRenderingContext.h" -#include "core/frame/Frame.h" +#include "core/frame/FrameHost.h" #include "core/frame/FrameView.h" -#include "core/page/Page.h" +#include "core/frame/LocalFrame.h" +#include "core/frame/Settings.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/svg/RenderSVGImage.h" #include "core/rendering/svg/RenderSVGResource.h" @@ -113,23 +114,28 @@ void SVGRenderingContext::prepareToRenderSVGContent(RenderObject* object, PaintI // Setup transparency layers before setting up SVG resources! bool isRenderingMask = isRenderingMaskImage(m_object); - float opacity = isRenderingMask ? 1 : style->opacity(); - blink::WebBlendMode blendMode = isRenderingMask ? blink::WebBlendModeNormal : style->blendMode(); - if (opacity < 1 || blendMode != blink::WebBlendModeNormal) { - FloatRect repaintRect = m_object->repaintRectInLocalCoordinates(); - - if (opacity < 1 || blendMode != blink::WebBlendModeNormal) { - m_paintInfo->context->clip(repaintRect); - if (blendMode != blink::WebBlendModeNormal) { - if (!(m_renderingFlags & RestoreGraphicsContext)) { - m_paintInfo->context->save(); - m_renderingFlags |= RestoreGraphicsContext; - } - m_paintInfo->context->setCompositeOperation(CompositeSourceOver, blendMode); + // RenderLayer takes care of root opacity. + float opacity = (object->isSVGRoot() || isRenderingMask) ? 1 : style->opacity(); + bool hasBlendMode = style->hasBlendMode() && !isRenderingMask; + + if (opacity < 1 || hasBlendMode || style->hasIsolation()) { + FloatRect repaintRect = m_object->paintInvalidationRectInLocalCoordinates(); + m_paintInfo->context->clip(repaintRect); + + if (hasBlendMode) { + if (!(m_renderingFlags & RestoreGraphicsContext)) { + m_paintInfo->context->save(); + m_renderingFlags |= RestoreGraphicsContext; } - m_paintInfo->context->beginTransparencyLayer(opacity); - m_renderingFlags |= EndOpacityLayer; + m_paintInfo->context->setCompositeOperation(CompositeSourceOver, style->blendMode()); } + + m_paintInfo->context->beginTransparencyLayer(opacity); + + if (hasBlendMode) + m_paintInfo->context->setCompositeOperation(CompositeSourceOver, blink::WebBlendModeNormal); + + m_renderingFlags |= EndOpacityLayer; } ClipPathOperation* clipPathOperation = style->clipPath(); @@ -197,20 +203,23 @@ float SVGRenderingContext::calculateScreenFontSizeScalingFactor(const RenderObje ASSERT(renderer); AffineTransform ctm; - calculateTransformationToOutermostCoordinateSystem(renderer, ctm); + // FIXME: calculateDeviceSpaceTransformation() queries layer compositing state - which is not + // supported during layout. Hence, the result may not include all CSS transforms. + calculateDeviceSpaceTransformation(renderer, ctm); return narrowPrecisionToFloat(sqrt((pow(ctm.xScale(), 2) + pow(ctm.yScale(), 2)) / 2)); } -void SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(const RenderObject* renderer, AffineTransform& absoluteTransform) +void SVGRenderingContext::calculateDeviceSpaceTransformation(const RenderObject* renderer, AffineTransform& absoluteTransform) { - ASSERT(renderer); - absoluteTransform = currentContentTransformation(); + // FIXME: trying to compute a device space transform at record time is wrong. All clients + // should be updated to avoid relying on this information, and the method should be removed. - float deviceScaleFactor = 1; - if (Page* page = renderer->document().page()) - deviceScaleFactor = page->deviceScaleFactor(); + ASSERT(renderer); + // We're about to possibly clear renderer, so save the deviceScaleFactor now. + float deviceScaleFactor = renderer->document().frameHost()->deviceScaleFactor(); // Walk up the render tree, accumulating SVG transforms. + absoluteTransform = currentContentTransformation(); while (renderer) { absoluteTransform = renderer->localToParentTransform() * absoluteTransform; if (renderer->isSVGRoot()) @@ -220,23 +229,22 @@ void SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(con // Continue walking up the layer tree, accumulating CSS transforms. RenderLayer* layer = renderer ? renderer->enclosingLayer() : 0; - while (layer) { - if (TransformationMatrix* layerTransform = layer->transform()) - absoluteTransform = layerTransform->toAffineTransform() * absoluteTransform; - + while (layer && layer->isAllowedToQueryCompositingState()) { // We can stop at compositing layers, to match the backing resolution. // FIXME: should we be computing the transform to the nearest composited layer, // or the nearest composited layer that does not paint into its ancestor? // I think this is the nearest composited ancestor since we will inherit its // transforms in the composited layer tree. - if (layer->hasCompositedLayerMapping()) + if (layer->compositingState() != NotComposited) break; + if (TransformationMatrix* layerTransform = layer->transform()) + absoluteTransform = layerTransform->toAffineTransform() * absoluteTransform; + layer = layer->parent(); } - if (deviceScaleFactor != 1) - absoluteTransform.scale(deviceScaleFactor); + absoluteTransform.scale(deviceScaleFactor); } void SVGRenderingContext::renderSubtree(GraphicsContext* context, RenderObject* item, const AffineTransform& subtreeContentTransformation) @@ -278,7 +286,7 @@ bool SVGRenderingContext::bufferForeground(OwnPtr<ImageBuffer>& imageBuffer) // Invalidate an existing buffer if the scale is not correct. if (imageBuffer) { - AffineTransform transform = m_paintInfo->context->getCTM(GraphicsContext::DefinitelyIncludeDeviceScale); + AffineTransform transform = m_paintInfo->context->getCTM(); IntSize expandedBoundingBox = expandedIntSize(boundingBox.size()); IntSize bufferSize(static_cast<int>(ceil(expandedBoundingBox.width() * transform.xScale())), static_cast<int>(ceil(expandedBoundingBox.height() * transform.yScale()))); if (bufferSize != imageBuffer->size()) diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderingContext.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderingContext.h index 742e0a09997..3fcda0ae099 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderingContext.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderingContext.h @@ -79,7 +79,7 @@ public: static void renderSubtree(GraphicsContext*, RenderObject*, const AffineTransform&); static float calculateScreenFontSizeScalingFactor(const RenderObject*); - static void calculateTransformationToOutermostCoordinateSystem(const RenderObject*, AffineTransform& absoluteTransform); + static void calculateDeviceSpaceTransformation(const RenderObject*, AffineTransform& absoluteTransform); static FloatRect clampedAbsoluteTargetRect(const FloatRect& absoluteTargetRect); static void clear2DRotation(AffineTransform&); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResources.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResources.cpp index 5c42dbcef69..dcb5113bff7 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResources.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResources.cpp @@ -20,7 +20,7 @@ #include "config.h" #include "core/rendering/svg/SVGResources.h" -#include "SVGNames.h" +#include "core/SVGNames.h" #include "core/rendering/style/SVGRenderStyle.h" #include "core/rendering/svg/RenderSVGResourceClipper.h" #include "core/rendering/svg/RenderSVGResourceFilter.h" @@ -38,6 +38,8 @@ namespace WebCore { +using namespace SVGNames; + SVGResources::SVGResources() : m_linkedResource(0) { @@ -49,39 +51,45 @@ static HashSet<AtomicString>& clipperFilterMaskerTags() if (s_tagList.isEmpty()) { // "container elements": http://www.w3.org/TR/SVG11/intro.html#TermContainerElement // "graphics elements" : http://www.w3.org/TR/SVG11/intro.html#TermGraphicsElement - s_tagList.add(SVGNames::aTag.localName()); - s_tagList.add(SVGNames::circleTag.localName()); - s_tagList.add(SVGNames::ellipseTag.localName()); - s_tagList.add(SVGNames::glyphTag.localName()); - s_tagList.add(SVGNames::gTag.localName()); - s_tagList.add(SVGNames::imageTag.localName()); - s_tagList.add(SVGNames::lineTag.localName()); - s_tagList.add(SVGNames::markerTag.localName()); - s_tagList.add(SVGNames::maskTag.localName()); - s_tagList.add(SVGNames::missing_glyphTag.localName()); - s_tagList.add(SVGNames::pathTag.localName()); - s_tagList.add(SVGNames::polygonTag.localName()); - s_tagList.add(SVGNames::polylineTag.localName()); - s_tagList.add(SVGNames::rectTag.localName()); - s_tagList.add(SVGNames::svgTag.localName()); - s_tagList.add(SVGNames::textTag.localName()); - s_tagList.add(SVGNames::useTag.localName()); + s_tagList.add(aTag.localName()); + s_tagList.add(circleTag.localName()); + s_tagList.add(ellipseTag.localName()); +#if ENABLE(SVG_FONTS) + s_tagList.add(glyphTag.localName()); +#endif + s_tagList.add(gTag.localName()); + s_tagList.add(imageTag.localName()); + s_tagList.add(lineTag.localName()); + s_tagList.add(markerTag.localName()); + s_tagList.add(maskTag.localName()); +#if ENABLE(SVG_FONTS) + s_tagList.add(missing_glyphTag.localName()); +#endif + s_tagList.add(pathTag.localName()); + s_tagList.add(polygonTag.localName()); + s_tagList.add(polylineTag.localName()); + s_tagList.add(rectTag.localName()); + s_tagList.add(svgTag.localName()); + s_tagList.add(textTag.localName()); + s_tagList.add(useTag.localName()); // Not listed in the definitions is the clipPath element, the SVG spec says though: // The "clipPath" element or any of its children can specify property "clip-path". // So we have to add clipPathTag here, otherwhise clip-path on clipPath will fail. // (Already mailed SVG WG, waiting for a solution) - s_tagList.add(SVGNames::clipPathTag.localName()); + s_tagList.add(clipPathTag.localName()); // Not listed in the definitions are the text content elements, though filter/clipper/masker on tspan/text/.. is allowed. // (Already mailed SVG WG, waiting for a solution) - s_tagList.add(SVGNames::altGlyphTag.localName()); - s_tagList.add(SVGNames::textPathTag.localName()); - s_tagList.add(SVGNames::tspanTag.localName()); +#if ENABLE(SVG_FONTS) + s_tagList.add(altGlyphTag.localName()); +#endif + s_tagList.add(textPathTag.localName()); + s_tagList.add(tspanTag.localName()); // Not listed in the definitions is the foreignObject element, but clip-path // is a supported attribute. - s_tagList.add(SVGNames::foreignObjectTag.localName()); + s_tagList.add(foreignObjectTag.localName()); // Elements that we ignore, as it doesn't make any sense. // defs, pattern, switch (FIXME: Mail SVG WG about these) @@ -91,34 +99,36 @@ static HashSet<AtomicString>& clipperFilterMaskerTags() return s_tagList; } -static HashSet<AtomicString>& markerTags() +bool SVGResources::supportsMarkers(const SVGElement& element) { DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ()); if (s_tagList.isEmpty()) { - s_tagList.add(SVGNames::lineTag.localName()); - s_tagList.add(SVGNames::pathTag.localName()); - s_tagList.add(SVGNames::polygonTag.localName()); - s_tagList.add(SVGNames::polylineTag.localName()); + s_tagList.add(lineTag.localName()); + s_tagList.add(pathTag.localName()); + s_tagList.add(polygonTag.localName()); + s_tagList.add(polylineTag.localName()); } - return s_tagList; + return s_tagList.contains(element.localName()); } static HashSet<AtomicString>& fillAndStrokeTags() { DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ()); if (s_tagList.isEmpty()) { - s_tagList.add(SVGNames::altGlyphTag.localName()); - s_tagList.add(SVGNames::circleTag.localName()); - s_tagList.add(SVGNames::ellipseTag.localName()); - s_tagList.add(SVGNames::lineTag.localName()); - s_tagList.add(SVGNames::pathTag.localName()); - s_tagList.add(SVGNames::polygonTag.localName()); - s_tagList.add(SVGNames::polylineTag.localName()); - s_tagList.add(SVGNames::rectTag.localName()); - s_tagList.add(SVGNames::textTag.localName()); - s_tagList.add(SVGNames::textPathTag.localName()); - s_tagList.add(SVGNames::tspanTag.localName()); +#if ENABLE(SVG_FONTS) + s_tagList.add(altGlyphTag.localName()); +#endif + s_tagList.add(circleTag.localName()); + s_tagList.add(ellipseTag.localName()); + s_tagList.add(lineTag.localName()); + s_tagList.add(pathTag.localName()); + s_tagList.add(polygonTag.localName()); + s_tagList.add(polylineTag.localName()); + s_tagList.add(rectTag.localName()); + s_tagList.add(textTag.localName()); + s_tagList.add(textPathTag.localName()); + s_tagList.add(tspanTag.localName()); } return s_tagList; @@ -128,37 +138,52 @@ static HashSet<AtomicString>& chainableResourceTags() { DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ()); if (s_tagList.isEmpty()) { - s_tagList.add(SVGNames::linearGradientTag.localName()); - s_tagList.add(SVGNames::filterTag.localName()); - s_tagList.add(SVGNames::patternTag.localName()); - s_tagList.add(SVGNames::radialGradientTag.localName()); + s_tagList.add(linearGradientTag.localName()); + s_tagList.add(filterTag.localName()); + s_tagList.add(patternTag.localName()); + s_tagList.add(radialGradientTag.localName()); } return s_tagList; } -static inline String targetReferenceFromResource(SVGElement* element) +static inline AtomicString targetReferenceFromResource(SVGElement& element) { String target; - if (element->hasTagName(SVGNames::patternTag)) - target = toSVGPatternElement(element)->hrefCurrentValue(); - else if (element->hasTagName(SVGNames::linearGradientTag) || element->hasTagName(SVGNames::radialGradientTag)) - target = toSVGGradientElement(element)->hrefCurrentValue(); - else if (element->hasTagName(SVGNames::filterTag)) - target = toSVGFilterElement(element)->hrefCurrentValue(); + if (isSVGPatternElement(element)) + target = toSVGPatternElement(element).href()->currentValue()->value(); + else if (isSVGGradientElement(element)) + target = toSVGGradientElement(element).href()->currentValue()->value(); + else if (isSVGFilterElement(element)) + target = toSVGFilterElement(element).href()->currentValue()->value(); else ASSERT_NOT_REACHED(); - return SVGURIReference::fragmentIdentifierFromIRIString(target, element->document()); + return SVGURIReference::fragmentIdentifierFromIRIString(target, element.treeScope()); +} + +static inline bool svgPaintTypeHasURL(SVGPaint::SVGPaintType paintType) +{ + switch (paintType) { + case SVGPaint::SVG_PAINTTYPE_URI_NONE: + case SVGPaint::SVG_PAINTTYPE_URI_CURRENTCOLOR: + case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR: + case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR: + case SVGPaint::SVG_PAINTTYPE_URI: + return true; + default: + break; + } + return false; } -static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document& document, const SVGPaint::SVGPaintType& paintType, const String& paintUri, AtomicString& id, bool& hasPendingResource) +static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(TreeScope& treeScope, const SVGPaint::SVGPaintType& paintType, const String& paintUri, AtomicString& id, bool& hasPendingResource) { - if (paintType != SVGPaint::SVG_PAINTTYPE_URI && paintType != SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) + if (!svgPaintTypeHasURL(paintType)) return 0; - id = SVGURIReference::fragmentIdentifierFromIRIString(paintUri, document); - RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id); + id = SVGURIReference::fragmentIdentifierFromIRIString(paintUri, treeScope); + RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(treeScope, id); if (!container) { hasPendingResource = true; return 0; @@ -171,10 +196,10 @@ static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document& return container; } -static inline void registerPendingResource(SVGDocumentExtensions* extensions, const AtomicString& id, SVGElement* element) +static inline void registerPendingResource(SVGDocumentExtensions& extensions, const AtomicString& id, SVGElement* element) { ASSERT(element); - extensions->addPendingResource(id, element); + extensions.addPendingResource(id, element); } bool SVGResources::hasResourceData() const @@ -206,10 +231,9 @@ PassOwnPtr<SVGResources> SVGResources::buildResources(const RenderObject* object if (!element) return nullptr; - Document& document = object->document(); + TreeScope& treeScope = element->treeScope(); - SVGDocumentExtensions* extensions = document.accessSVGExtensions(); - ASSERT(extensions); + SVGDocumentExtensions& extensions = object->document().accessSVGExtensions(); const AtomicString& tagName = element->localName(); if (tagName.isNull()) @@ -218,35 +242,35 @@ PassOwnPtr<SVGResources> SVGResources::buildResources(const RenderObject* object OwnPtr<SVGResources> resources; if (clipperFilterMaskerTags().contains(tagName)) { if (style->hasClipper()) { - AtomicString id(style->clipperResource()); - if (!ensureResources(resources)->setClipper(getRenderSVGResourceById<RenderSVGResourceClipper>(document, id))) + AtomicString id = style->clipperResource(); + if (!ensureResources(resources)->setClipper(getRenderSVGResourceById<RenderSVGResourceClipper>(treeScope, id))) registerPendingResource(extensions, id, element); } if (style->hasFilter()) { - AtomicString id(style->filterResource()); - if (!ensureResources(resources)->setFilter(getRenderSVGResourceById<RenderSVGResourceFilter>(document, id))) + AtomicString id = style->filterResource(); + if (!ensureResources(resources)->setFilter(getRenderSVGResourceById<RenderSVGResourceFilter>(treeScope, id))) registerPendingResource(extensions, id, element); } if (style->hasMasker()) { - AtomicString id(style->maskerResource()); - if (!ensureResources(resources)->setMasker(getRenderSVGResourceById<RenderSVGResourceMasker>(document, id))) + AtomicString id = style->maskerResource(); + if (!ensureResources(resources)->setMasker(getRenderSVGResourceById<RenderSVGResourceMasker>(treeScope, id))) registerPendingResource(extensions, id, element); } } - if (markerTags().contains(tagName) && style->hasMarkers()) { - AtomicString markerStartId(style->markerStartResource()); - if (!ensureResources(resources)->setMarkerStart(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerStartId))) + if (style->hasMarkers() && supportsMarkers(*element)) { + const AtomicString& markerStartId = style->markerStartResource(); + if (!ensureResources(resources)->setMarkerStart(getRenderSVGResourceById<RenderSVGResourceMarker>(treeScope, markerStartId))) registerPendingResource(extensions, markerStartId, element); - AtomicString markerMidId(style->markerMidResource()); - if (!ensureResources(resources)->setMarkerMid(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerMidId))) + const AtomicString& markerMidId = style->markerMidResource(); + if (!ensureResources(resources)->setMarkerMid(getRenderSVGResourceById<RenderSVGResourceMarker>(treeScope, markerMidId))) registerPendingResource(extensions, markerMidId, element); - AtomicString markerEndId(style->markerEndResource()); - if (!ensureResources(resources)->setMarkerEnd(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerEndId))) + const AtomicString& markerEndId = style->markerEndResource(); + if (!ensureResources(resources)->setMarkerEnd(getRenderSVGResourceById<RenderSVGResourceMarker>(treeScope, style->markerEndResource()))) registerPendingResource(extensions, markerEndId, element); } @@ -254,7 +278,7 @@ PassOwnPtr<SVGResources> SVGResources::buildResources(const RenderObject* object if (style->hasFill()) { bool hasPendingResource = false; AtomicString id; - RenderSVGResourceContainer* resource = paintingResourceFromSVGPaint(document, style->fillPaintType(), style->fillPaintUri(), id, hasPendingResource); + RenderSVGResourceContainer* resource = paintingResourceFromSVGPaint(treeScope, style->fillPaintType(), style->fillPaintUri(), id, hasPendingResource); if (!ensureResources(resources)->setFill(resource) && hasPendingResource) { registerPendingResource(extensions, id, element); } @@ -263,7 +287,7 @@ PassOwnPtr<SVGResources> SVGResources::buildResources(const RenderObject* object if (style->hasStroke()) { bool hasPendingResource = false; AtomicString id; - RenderSVGResourceContainer* resource = paintingResourceFromSVGPaint(document, style->strokePaintType(), style->strokePaintUri(), id, hasPendingResource); + RenderSVGResourceContainer* resource = paintingResourceFromSVGPaint(treeScope, style->strokePaintType(), style->strokePaintUri(), id, hasPendingResource); if (!ensureResources(resources)->setStroke(resource) && hasPendingResource) { registerPendingResource(extensions, id, element); } @@ -271,8 +295,8 @@ PassOwnPtr<SVGResources> SVGResources::buildResources(const RenderObject* object } if (chainableResourceTags().contains(tagName)) { - AtomicString id(targetReferenceFromResource(element)); - if (!ensureResources(resources)->setLinkedResource(getRenderSVGResourceContainerById(document, id))) + AtomicString id = targetReferenceFromResource(*element); + if (!ensureResources(resources)->setLinkedResource(getRenderSVGResourceContainerById(treeScope, id))) registerPendingResource(extensions, id, element); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResources.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResources.h index 8eb10adcb4e..41cdf2569d8 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResources.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResources.h @@ -20,6 +20,7 @@ #ifndef SVGResources_h #define SVGResources_h +#include "wtf/FastAllocBase.h" #include "wtf/HashSet.h" #include "wtf/Noncopyable.h" #include "wtf/OwnPtr.h" @@ -27,13 +28,13 @@ namespace WebCore { -class Document; class RenderObject; class RenderSVGResourceClipper; class RenderSVGResourceContainer; class RenderSVGResourceFilter; class RenderSVGResourceMarker; class RenderSVGResourceMasker; +class SVGElement; class SVGRenderStyle; // Holds a set of resources associated with a RenderObject @@ -45,6 +46,8 @@ public: static PassOwnPtr<SVGResources> buildResources(const RenderObject*, const SVGRenderStyle*); void layoutIfNeeded(); + static bool supportsMarkers(const SVGElement&); + // Ordinary resources RenderSVGResourceClipper* clipper() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->clipper : 0; } RenderSVGResourceMarker* markerStart() const { return m_markerData ? m_markerData->markerStart : 0; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCache.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCache.cpp index 7a8ed18b4d8..b8ba7101ded 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCache.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCache.cpp @@ -20,7 +20,7 @@ #include "config.h" #include "core/rendering/svg/SVGResourcesCache.h" -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/rendering/svg/RenderSVGResourceContainer.h" #include "core/rendering/svg/SVGResources.h" #include "core/rendering/svg/SVGResourcesCycleSolver.h" @@ -51,7 +51,7 @@ void SVGResourcesCache::addResourcesFromRenderObject(RenderObject* object, const return; // Put object in cache. - SVGResources* resources = m_cache.set(object, newResources.release()).iterator->value.get(); + SVGResources* resources = m_cache.set(object, newResources.release()).storedValue->value.get(); // Run cycle-detection _afterwards_, so self-references can be caught as well. SVGResourcesCycleSolver solver(object, resources); @@ -85,10 +85,8 @@ static inline SVGResourcesCache* resourcesCacheFromRenderObject(const RenderObje { Document& document = renderer->document(); - SVGDocumentExtensions* extensions = document.accessSVGExtensions(); - ASSERT(extensions); - - SVGResourcesCache* cache = extensions->resourcesCache(); + SVGDocumentExtensions& extensions = document.accessSVGExtensions(); + SVGResourcesCache* cache = extensions.resourcesCache(); ASSERT(cache); return cache; @@ -124,11 +122,11 @@ void SVGResourcesCache::clientStyleChanged(RenderObject* renderer, StyleDifferen ASSERT(renderer->node()); ASSERT(renderer->node()->isSVGElement()); - if (diff == StyleDifferenceEqual || !renderer->parent()) + if (diff.hasNoChange() || !renderer->parent()) return; // In this case the proper SVGFE*Element will decide whether the modified CSS properties require a relayout or repaint. - if (renderer->isSVGResourceFilterPrimitive() && (diff == StyleDifferenceRepaint || diff == StyleDifferenceRepaintIfTextOrColorChange)) + if (renderer->isSVGResourceFilterPrimitive() && !diff.needsLayout()) return; // Dynamic changes of CSS properties like 'clip-path' may require us to recompute the associated resources for a renderer. @@ -194,9 +192,9 @@ void SVGResourcesCache::resourceDestroyed(RenderSVGResourceContainer* resource) // Mark users of destroyed resources as pending resolution based on the id of the old resource. Element* resourceElement = resource->element(); Element* clientElement = toElement(it->key->node()); - SVGDocumentExtensions* extensions = clientElement->document().accessSVGExtensions(); + SVGDocumentExtensions& extensions = clientElement->document().accessSVGExtensions(); - extensions->addPendingResource(resourceElement->fastGetAttribute(HTMLNames::idAttr), clientElement); + extensions.addPendingResource(resourceElement->fastGetAttribute(HTMLNames::idAttr), clientElement); } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCache.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCache.h index ff5e9f903af..7bf878e7237 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCache.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCache.h @@ -20,7 +20,8 @@ #ifndef SVGResourcesCache_h #define SVGResourcesCache_h -#include "core/rendering/style/RenderStyleConstants.h" +#include "core/rendering/style/StyleDifference.h" +#include "wtf/FastAllocBase.h" #include "wtf/HashMap.h" #include "wtf/Noncopyable.h" #include "wtf/OwnPtr.h" diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCycleSolver.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCycleSolver.cpp index efa1b933394..ae7e954fb04 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCycleSolver.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCycleSolver.cpp @@ -47,117 +47,83 @@ SVGResourcesCycleSolver::~SVGResourcesCycleSolver() { } -bool SVGResourcesCycleSolver::resourceContainsCycles(RenderObject* renderer) const -{ - ASSERT(renderer); - - // First operate on the resources of the given renderer. - // <marker id="a"> <path marker-start="url(#b)"/> ... - // <marker id="b" marker-start="url(#a)"/> - if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer)) { - HashSet<RenderSVGResourceContainer*> resourceSet; - resources->buildSetOfResources(resourceSet); - - // Walk all resources and check wheter they reference any resource contained in the resources set. - HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end(); - for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it) { - if (m_allResources.contains(*it)) - return true; - } - } +struct ActiveFrame { + typedef SVGResourcesCycleSolver::ResourceSet ResourceSet; - // Then operate on the child resources of the given renderer. - // <marker id="a"> <path marker-start="url(#b)"/> ... - // <marker id="b"> <path marker-start="url(#a)"/> ... - for (RenderObject* child = renderer->firstChild(); child; child = child->nextSibling()) { - SVGResources* childResources = SVGResourcesCache::cachedResourcesForRenderObject(child); - if (!childResources) - continue; + ActiveFrame(ResourceSet& activeSet, RenderSVGResourceContainer* resource) + : m_activeSet(activeSet) + , m_resource(resource) + { + m_activeSet.add(m_resource); + } + ~ActiveFrame() + { + m_activeSet.remove(m_resource); + } - // A child of the given 'resource' contains resources. - HashSet<RenderSVGResourceContainer*> childSet; - childResources->buildSetOfResources(childSet); + ResourceSet& m_activeSet; + RenderSVGResourceContainer* m_resource; +}; - // Walk all child resources and check wheter they reference any resource contained in the resources set. - HashSet<RenderSVGResourceContainer*>::iterator end = childSet.end(); - for (HashSet<RenderSVGResourceContainer*>::iterator it = childSet.begin(); it != end; ++it) { - if (m_allResources.contains(*it)) - return true; +bool SVGResourcesCycleSolver::resourceContainsCycles(RenderSVGResourceContainer* resource) +{ + // If we've traversed this sub-graph before and no cycles were observed, then + // reuse that result. + if (m_dagCache.contains(resource)) + return false; + + ActiveFrame frame(m_activeResources, resource); + + RenderObject* node = resource; + while (node) { + // Skip subtrees which are themselves resources. (They will be + // processed - if needed - when they are actually referenced.) + if (node != resource && node->isSVGResourceContainer()) { + node = node->nextInPreOrderAfterChildren(resource); + continue; } - - // Walk children recursively, stop immediately if we found a cycle - if (resourceContainsCycles(child)) - return true; + if (SVGResources* nodeResources = SVGResourcesCache::cachedResourcesForRenderObject(node)) { + // Fetch all the resources referenced by |node|. + ResourceSet nodeSet; + nodeResources->buildSetOfResources(nodeSet); + + // Iterate resources referenced by |node|. + ResourceSet::iterator end = nodeSet.end(); + for (ResourceSet::iterator it = nodeSet.begin(); it != end; ++it) { + if (m_activeResources.contains(*it) || resourceContainsCycles(*it)) + return true; + } + } + node = node->nextInPreOrder(resource); } + // No cycles found in (or from) this resource. Add it to the "DAG cache". + m_dagCache.add(resource); return false; } void SVGResourcesCycleSolver::resolveCycles() { - ASSERT(m_allResources.isEmpty()); - -#if DEBUG_CYCLE_DETECTION > 0 - fprintf(stderr, "\nBefore cycle detection:\n"); - m_resources->dump(m_renderer); -#endif - - // Stash all resources into a HashSet for the ease of traversing. - HashSet<RenderSVGResourceContainer*> localResources; - m_resources->buildSetOfResources(localResources); - ASSERT(!localResources.isEmpty()); - - // Add all parent resource containers to the HashSet. - HashSet<RenderSVGResourceContainer*> parentResources; - RenderObject* parent = m_renderer->parent(); - while (parent) { - if (parent->isSVGResourceContainer()) - parentResources.add(toRenderSVGResourceContainer(parent)); - parent = parent->parent(); - } + ASSERT(m_activeResources.isEmpty()); -#if DEBUG_CYCLE_DETECTION > 0 - fprintf(stderr, "\nDetecting wheter any resources references any of following objects:\n"); - { - fprintf(stderr, "Local resources:\n"); - HashSet<RenderSVGResourceContainer*>::iterator end = localResources.end(); - for (HashSet<RenderSVGResourceContainer*>::iterator it = localResources.begin(); it != end; ++it) - fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node()); - - fprintf(stderr, "Parent resources:\n"); - end = parentResources.end(); - for (HashSet<RenderSVGResourceContainer*>::iterator it = parentResources.begin(); it != end; ++it) - fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node()); - } -#endif - - // Build combined set of local and parent resources. - m_allResources = localResources; - HashSet<RenderSVGResourceContainer*>::iterator end = parentResources.end(); - for (HashSet<RenderSVGResourceContainer*>::iterator it = parentResources.begin(); it != end; ++it) - m_allResources.add(*it); - - // If we're a resource, add ourselves to the HashSet. + // If the starting RenderObject is a resource container itself, then add it + // to the active set (to break direct self-references.) if (m_renderer->isSVGResourceContainer()) - m_allResources.add(toRenderSVGResourceContainer(m_renderer)); + m_activeResources.add(toRenderSVGResourceContainer(m_renderer)); - ASSERT(!m_allResources.isEmpty()); + ResourceSet localResources; + m_resources->buildSetOfResources(localResources); - // The job of this function is to determine wheter any of the 'resources' associated with the given 'renderer' - // references us (or wheter any of its kids references us) -> that's a cycle, we need to find and break it. - end = localResources.end(); - for (HashSet<RenderSVGResourceContainer*>::iterator it = localResources.begin(); it != end; ++it) { - RenderSVGResourceContainer* resource = *it; - if (parentResources.contains(resource) || resourceContainsCycles(resource)) - breakCycle(resource); + // This performs a depth-first search for a back-edge in all the + // (potentially disjoint) graphs formed by the resources referenced by + // |m_renderer|. + ResourceSet::iterator end = localResources.end(); + for (ResourceSet::iterator it = localResources.begin(); it != end; ++it) { + if (m_activeResources.contains(*it) || resourceContainsCycles(*it)) + breakCycle(*it); } -#if DEBUG_CYCLE_DETECTION > 0 - fprintf(stderr, "\nAfter cycle detection:\n"); - m_resources->dump(m_renderer); -#endif - - m_allResources.clear(); + m_activeResources.clear(); } void SVGResourcesCycleSolver::breakCycle(RenderSVGResourceContainer* resourceLeadingToCycle) diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCycleSolver.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCycleSolver.h index cadaa5a311e..aadd9f6fa54 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCycleSolver.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCycleSolver.h @@ -37,13 +37,17 @@ public: void resolveCycles(); + typedef HashSet<RenderSVGResourceContainer*> ResourceSet; + private: - bool resourceContainsCycles(RenderObject*) const; + bool resourceContainsCycles(RenderSVGResourceContainer*); void breakCycle(RenderSVGResourceContainer*); RenderObject* m_renderer; SVGResources* m_resources; - HashSet<RenderSVGResourceContainer*> m_allResources; + + ResourceSet m_activeResources; + ResourceSet m_dagCache; }; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRootInlineBox.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRootInlineBox.cpp index ec9a953d1b3..4cd80101e37 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRootInlineBox.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRootInlineBox.cpp @@ -24,7 +24,6 @@ #include "config.h" #include "core/rendering/svg/SVGRootInlineBox.h" -#include "SVGNames.h" #include "core/rendering/svg/RenderSVGInlineText.h" #include "core/rendering/svg/RenderSVGText.h" #include "core/rendering/svg/SVGInlineFlowBox.h" @@ -33,15 +32,12 @@ namespace WebCore { -void SVGRootInlineBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUnit, LayoutUnit) +void SVGRootInlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit, LayoutUnit) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(!paintInfo.context->paintingDisabled()); - RenderObject* boxRenderer = renderer(); - ASSERT(boxRenderer); - - bool isPrinting = renderer()->document().printing(); + bool isPrinting = renderer().document().printing(); bool hasSelection = !isPrinting && selectionState() != RenderObject::SelectionNone; PaintInfo childPaintInfo(paintInfo); @@ -54,35 +50,29 @@ void SVGRootInlineBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni } } - SVGRenderingContext renderingContext(boxRenderer, paintInfo, SVGRenderingContext::SaveGraphicsContext); + SVGRenderingContext renderingContext(&renderer(), paintInfo, SVGRenderingContext::SaveGraphicsContext); if (renderingContext.isRenderingPrepared()) { - for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { - if (child->isSVGInlineTextBox()) - SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(toSVGInlineTextBox(child)->textRenderer())); - - child->paint(paintInfo, LayoutPoint(), 0, 0); - } + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) + child->paint(paintInfo, paintOffset, 0, 0); } } -void SVGRootInlineBox::markDirty(bool dirty) +void SVGRootInlineBox::markDirty() { - if (dirty) - for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) - child->markDirty(true); - RootInlineBox::markDirty(dirty); + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) + child->markDirty(); + RootInlineBox::markDirty(); } void SVGRootInlineBox::computePerCharacterLayoutInformation() { - RenderSVGText* textRoot = toRenderSVGText(block()); - ASSERT(textRoot); + RenderSVGText& textRoot = toRenderSVGText(block()); - Vector<SVGTextLayoutAttributes*>& layoutAttributes = textRoot->layoutAttributes(); + Vector<SVGTextLayoutAttributes*>& layoutAttributes = textRoot.layoutAttributes(); if (layoutAttributes.isEmpty()) return; - if (textRoot->needsReordering()) + if (textRoot.needsReordering()) reorderValueLists(layoutAttributes); // Perform SVG text layout phase two (see SVGTextLayoutEngine for details). @@ -103,24 +93,23 @@ void SVGRootInlineBox::layoutCharactersInTextBoxes(InlineFlowBox* start, SVGText { for (InlineBox* child = start->firstChild(); child; child = child->nextOnLine()) { if (child->isSVGInlineTextBox()) { - ASSERT(child->renderer()); - ASSERT(child->renderer()->isSVGInlineText()); + ASSERT(child->renderer().isSVGInlineText()); characterLayout.layoutInlineTextBox(toSVGInlineTextBox(child)); } else { // Skip generated content. - Node* node = child->renderer()->node(); + Node* node = child->renderer().node(); if (!node) continue; SVGInlineFlowBox* flowBox = toSVGInlineFlowBox(child); - bool isTextPath = node->hasTagName(SVGNames::textPathTag); + bool isTextPath = isSVGTextPathElement(*node); if (isTextPath) { // Build text chunks for all <textPath> children, using the line layout algorithm. // This is needeed as text-anchor is just an additional startOffset for text paths. SVGTextLayoutEngine lineLayout(characterLayout.layoutAttributes()); layoutCharactersInTextBoxes(flowBox, lineLayout); - characterLayout.beginTextPathLayout(child->renderer(), lineLayout); + characterLayout.beginTextPathLayout(&child->renderer(), lineLayout); } layoutCharactersInTextBoxes(flowBox, characterLayout); @@ -136,8 +125,7 @@ void SVGRootInlineBox::layoutChildBoxes(InlineFlowBox* start, FloatRect* childRe for (InlineBox* child = start->firstChild(); child; child = child->nextOnLine()) { FloatRect boxRect; if (child->isSVGInlineTextBox()) { - ASSERT(child->renderer()); - ASSERT(child->renderer()->isSVGInlineText()); + ASSERT(child->renderer().isSVGInlineText()); SVGInlineTextBox* textBox = toSVGInlineTextBox(child); boxRect = textBox->calculateBoundaries(); @@ -147,7 +135,7 @@ void SVGRootInlineBox::layoutChildBoxes(InlineFlowBox* start, FloatRect* childRe textBox->setLogicalHeight(boxRect.height()); } else { // Skip generated content. - if (!child->renderer()->node()) + if (!child->renderer().node()) continue; SVGInlineFlowBox* flowBox = toSVGInlineFlowBox(child); @@ -166,18 +154,17 @@ void SVGRootInlineBox::layoutChildBoxes(InlineFlowBox* start, FloatRect* childRe void SVGRootInlineBox::layoutRootBox(const FloatRect& childRect) { - RenderBlockFlow* parentBlock = block(); - ASSERT(parentBlock); + RenderBlockFlow& parentBlock = block(); // Finally, assign the root block position, now that all content is laid out. LayoutRect boundingRect = enclosingLayoutRect(childRect); - parentBlock->setLocation(boundingRect.location()); - parentBlock->setSize(boundingRect.size()); + parentBlock.setLocation(boundingRect.location()); + parentBlock.setSize(boundingRect.size()); // Position all children relative to the parent block. for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { // Skip generated content. - if (!child->renderer()->node()) + if (!child->renderer().node()) continue; child->adjustPosition(-childRect.x(), -childRect.y()); } @@ -221,21 +208,11 @@ static inline void swapItemsInLayoutAttributes(SVGTextLayoutAttributes* firstAtt SVGCharacterDataMap::iterator itLast = lastAttributes->characterDataMap().find(lastPosition + 1); bool firstPresent = itFirst != firstAttributes->characterDataMap().end(); bool lastPresent = itLast != lastAttributes->characterDataMap().end(); - if (!firstPresent && !lastPresent) + // We only want to perform the swap if both inline boxes are absolutely + // positioned. + if (!firstPresent || !lastPresent) return; - - if (firstPresent && lastPresent) { - std::swap(itFirst->value, itLast->value); - return; - } - - if (firstPresent && !lastPresent) { - lastAttributes->characterDataMap().set(lastPosition + 1, itFirst->value); - return; - } - - // !firstPresent && lastPresent - firstAttributes->characterDataMap().set(firstPosition + 1, itLast->value); + std::swap(itFirst->value, itLast->value); } static inline void findFirstAndLastAttributesInVector(Vector<SVGTextLayoutAttributes*>& attributes, RenderSVGInlineText* firstContext, RenderSVGInlineText* lastContext, @@ -282,12 +259,12 @@ static inline void reverseInlineBoxRangeAndValueListsIfNeeded(void* userData, Ve // Reordering is only necessary for BiDi text that is _absolutely_ positioned. if (firstTextBox->len() == 1 && firstTextBox->len() == lastTextBox->len()) { - RenderSVGInlineText* firstContext = toRenderSVGInlineText(firstTextBox->textRenderer()); - RenderSVGInlineText* lastContext = toRenderSVGInlineText(lastTextBox->textRenderer()); + RenderSVGInlineText& firstContext = toRenderSVGInlineText(firstTextBox->textRenderer()); + RenderSVGInlineText& lastContext = toRenderSVGInlineText(lastTextBox->textRenderer()); SVGTextLayoutAttributes* firstAttributes = 0; SVGTextLayoutAttributes* lastAttributes = 0; - findFirstAndLastAttributesInVector(attributes, firstContext, lastContext, firstAttributes, lastAttributes); + findFirstAndLastAttributesInVector(attributes, &firstContext, &lastContext, firstAttributes, lastAttributes); swapItemsInLayoutAttributes(firstAttributes, lastAttributes, firstTextBox->start(), lastTextBox->start()); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRootInlineBox.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRootInlineBox.h index efbe2f6b79b..862c9b24a4e 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRootInlineBox.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRootInlineBox.h @@ -29,24 +29,22 @@ namespace WebCore { -class SVGInlineTextBox; - class SVGRootInlineBox FINAL : public RootInlineBox { public: - SVGRootInlineBox(RenderBlockFlow* block) + SVGRootInlineBox(RenderBlockFlow& block) : RootInlineBox(block) , m_logicalHeight(0) { } - virtual bool isSVGRootInlineBox() const OVERRIDE FINAL { return true; } + virtual bool isSVGRootInlineBox() const OVERRIDE { return true; } - virtual float virtualLogicalHeight() const OVERRIDE FINAL { return m_logicalHeight; } + virtual float virtualLogicalHeight() const OVERRIDE { return m_logicalHeight; } void setLogicalHeight(float height) { m_logicalHeight = height; } - virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE FINAL; + virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; - virtual void markDirty(bool dirty = true) OVERRIDE FINAL; + virtual void markDirty() OVERRIDE; void computePerCharacterLayoutInformation(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextChunkBuilder.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextChunkBuilder.cpp index d26d868fff1..488fbd4bddd 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextChunkBuilder.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextChunkBuilder.cpp @@ -91,10 +91,9 @@ void SVGTextChunkBuilder::addTextChunk(Vector<SVGInlineTextBox*>& lineLayoutBoxe SVGInlineTextBox* textBox = lineLayoutBoxes[boxStart]; ASSERT(textBox); - RenderSVGInlineText* textRenderer = toRenderSVGInlineText(textBox->textRenderer()); - ASSERT(textRenderer); + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(textBox->textRenderer()); - const RenderStyle* style = textRenderer->style(); + const RenderStyle* style = toRenderSVGInlineText(textBox->textRenderer()).style(); ASSERT(style); const SVGRenderStyle* svgStyle = style->svgStyle(); @@ -125,11 +124,14 @@ void SVGTextChunkBuilder::addTextChunk(Vector<SVGInlineTextBox*>& lineLayoutBoxe // Handle 'lengthAdjust' property. float desiredTextLength = 0; - if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textRenderer->parent())) { + if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textRenderer.parent())) { SVGLengthContext lengthContext(textContentElement); - desiredTextLength = textContentElement->specifiedTextLength().value(lengthContext); + if (textContentElement->textLengthIsSpecifiedByUser()) + desiredTextLength = textContentElement->textLength()->currentValue()->value(lengthContext); + else + desiredTextLength = 0; - switch (textContentElement->lengthAdjustCurrentValue()) { + switch (textContentElement->lengthAdjust()->currentValue()->enumValue()) { case SVGLengthAdjustUnknown: break; case SVGLengthAdjustSpacing: diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutAttributesBuilder.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutAttributesBuilder.cpp index 7c65a7e55e6..cbf018dc87a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutAttributesBuilder.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutAttributesBuilder.cpp @@ -23,6 +23,7 @@ #include "core/rendering/svg/RenderSVGInlineText.h" #include "core/rendering/svg/RenderSVGText.h" +#include "core/rendering/svg/SVGTextMetricsBuilder.h" #include "core/svg/SVGTextPositioningElement.h" namespace WebCore { @@ -53,7 +54,7 @@ void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextRenderer(Render buildCharacterDataMap(textRoot); } - m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, text, m_characterDataMap); + SVGTextMetricsBuilder::buildMetricsAndLayoutAttributes(textRoot, text, m_characterDataMap); } bool SVGTextLayoutAttributesBuilder::buildLayoutAttributesForForSubtree(RenderSVGText* textRoot) @@ -72,14 +73,14 @@ bool SVGTextLayoutAttributesBuilder::buildLayoutAttributesForForSubtree(RenderSV return false; buildCharacterDataMap(textRoot); - m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, 0, m_characterDataMap); + SVGTextMetricsBuilder::buildMetricsAndLayoutAttributes(textRoot, 0, m_characterDataMap); return true; } void SVGTextLayoutAttributesBuilder::rebuildMetricsForTextRenderer(RenderSVGInlineText* text) { ASSERT(text); - m_metricsBuilder.measureTextRenderer(text); + SVGTextMetricsBuilder::measureTextRenderer(text); } static inline void processRenderSVGInlineText(RenderSVGInlineText* text, unsigned& atCharacter, UChar& lastCharacter) @@ -104,7 +105,7 @@ void SVGTextLayoutAttributesBuilder::collectTextPositioningElements(RenderObject { ASSERT(!start->isSVGText() || m_textPositions.isEmpty()); - for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { + for (RenderObject* child = start->slowFirstChild(); child; child = child->nextSibling()) { if (child->isSVGInlineText()) { processRenderSVGInlineText(toRenderSVGInlineText(child), m_textLength, lastCharacter); continue; @@ -163,43 +164,43 @@ void SVGTextLayoutAttributesBuilder::buildCharacterDataMap(RenderSVGText* textRo static inline void updateCharacterData(unsigned i, float& lastRotation, SVGCharacterData& data, const SVGLengthContext& lengthContext, const SVGLengthList* xList, const SVGLengthList* yList, const SVGLengthList* dxList, const SVGLengthList* dyList, const SVGNumberList* rotateList) { if (xList) - data.x = xList->at(i).value(lengthContext); + data.x = xList->at(i)->value(lengthContext); if (yList) - data.y = yList->at(i).value(lengthContext); + data.y = yList->at(i)->value(lengthContext); if (dxList) - data.dx = dxList->at(i).value(lengthContext); + data.dx = dxList->at(i)->value(lengthContext); if (dyList) - data.dy = dyList->at(i).value(lengthContext); + data.dy = dyList->at(i)->value(lengthContext); if (rotateList) { - data.rotate = rotateList->at(i).value(); + data.rotate = rotateList->at(i)->value(); lastRotation = data.rotate; } } void SVGTextLayoutAttributesBuilder::fillCharacterDataMap(const TextPosition& position) { - const SVGLengthList& xList = position.element->xCurrentValue(); - const SVGLengthList& yList = position.element->yCurrentValue(); - const SVGLengthList& dxList = position.element->dxCurrentValue(); - const SVGLengthList& dyList = position.element->dyCurrentValue(); - const SVGNumberList& rotateList = position.element->rotateCurrentValue(); - - unsigned xListSize = xList.size(); - unsigned yListSize = yList.size(); - unsigned dxListSize = dxList.size(); - unsigned dyListSize = dyList.size(); - unsigned rotateListSize = rotateList.size(); + RefPtr<SVGLengthList> xList = position.element->x()->currentValue(); + RefPtr<SVGLengthList> yList = position.element->y()->currentValue(); + RefPtr<SVGLengthList> dxList = position.element->dx()->currentValue(); + RefPtr<SVGLengthList> dyList = position.element->dy()->currentValue(); + RefPtr<SVGNumberList> rotateList = position.element->rotate()->currentValue(); + + unsigned xListSize = xList->length(); + unsigned yListSize = yList->length(); + unsigned dxListSize = dxList->length(); + unsigned dyListSize = dyList->length(); + unsigned rotateListSize = rotateList->length(); if (!xListSize && !yListSize && !dxListSize && !dyListSize && !rotateListSize) return; float lastRotation = SVGTextLayoutAttributes::emptyValue(); SVGLengthContext lengthContext(position.element); for (unsigned i = 0; i < position.length; ++i) { - const SVGLengthList* xListPtr = i < xListSize ? &xList : 0; - const SVGLengthList* yListPtr = i < yListSize ? &yList : 0; - const SVGLengthList* dxListPtr = i < dxListSize ? &dxList : 0; - const SVGLengthList* dyListPtr = i < dyListSize ? &dyList : 0; - const SVGNumberList* rotateListPtr = i < rotateListSize ? &rotateList : 0; + const SVGLengthList* xListPtr = i < xListSize ? xList.get() : 0; + const SVGLengthList* yListPtr = i < yListSize ? yList.get() : 0; + const SVGLengthList* dxListPtr = i < dxListSize ? dxList.get() : 0; + const SVGLengthList* dyListPtr = i < dyListSize ? dyList.get() : 0; + const SVGNumberList* rotateListPtr = i < rotateListSize ? rotateList.get() : 0; if (!xListPtr && !yListPtr && !dxListPtr && !dyListPtr && !rotateListPtr) break; @@ -218,7 +219,7 @@ void SVGTextLayoutAttributesBuilder::fillCharacterDataMap(const TextPosition& po if (lastRotation == SVGTextLayoutAttributes::emptyValue()) return; - for (unsigned i = rotateList.size(); i < position.length; ++i) { + for (unsigned i = rotateList->length(); i < position.length; ++i) { SVGCharacterDataMap::iterator it = m_characterDataMap.find(position.start + i + 1); if (it == m_characterDataMap.end()) { SVGCharacterData data; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutAttributesBuilder.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutAttributesBuilder.h index d92c125f47f..82d2d064660 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutAttributesBuilder.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutAttributesBuilder.h @@ -20,7 +20,7 @@ #ifndef SVGTextLayoutAttributesBuilder_h #define SVGTextLayoutAttributesBuilder_h -#include "core/rendering/svg/SVGTextMetricsBuilder.h" +#include "core/rendering/svg/SVGTextLayoutAttributes.h" #include "wtf/Vector.h" namespace WebCore { @@ -73,7 +73,6 @@ private: unsigned m_textLength; Vector<TextPosition> m_textPositions; SVGCharacterDataMap m_characterDataMap; - SVGTextMetricsBuilder m_metricsBuilder; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngine.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngine.cpp index 0ade353f4a7..fc5dc792329 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngine.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngine.cpp @@ -47,6 +47,7 @@ SVGTextLayoutEngine::SVGTextLayoutEngine(Vector<SVGTextLayoutAttributes*>& layou , m_dy(0) , m_isVerticalText(false) , m_inPathLayout(false) + , m_textPathCalculator(0) , m_textPathLength(0) , m_textPathCurrentOffset(0) , m_textPathSpacing(0) @@ -148,7 +149,7 @@ bool SVGTextLayoutEngine::parentDefinesTextLength(RenderObject* parent) const while (currentParent) { if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(currentParent)) { SVGLengthContext lengthContext(textContentElement); - if (textContentElement->lengthAdjustCurrentValue() == SVGLengthAdjustSpacing && textContentElement->specifiedTextLength().value(lengthContext) > 0) + if (textContentElement->lengthAdjust()->currentValue()->enumValue() == SVGLengthAdjustSpacing && textContentElement->textLengthIsSpecifiedByUser()) return true; } @@ -169,11 +170,12 @@ void SVGTextLayoutEngine::beginTextPathLayout(RenderObject* object, SVGTextLayou m_inPathLayout = true; RenderSVGTextPath* textPath = toRenderSVGTextPath(object); - m_textPath = textPath->layoutPath(); - if (m_textPath.isEmpty()) + Path path = textPath->layoutPath(); + if (path.isEmpty()) return; + m_textPathCalculator = new Path::PositionCalculator(path); m_textPathStartOffset = textPath->startOffset(); - m_textPathLength = m_textPath.length(); + m_textPathLength = path.length(); if (m_textPathStartOffset > 0 && m_textPathStartOffset <= 1) m_textPathStartOffset *= m_textPathLength; @@ -206,8 +208,11 @@ void SVGTextLayoutEngine::beginTextPathLayout(RenderObject* object, SVGTextLayou if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textPath)) { SVGLengthContext lengthContext(textContentElement); - lengthAdjust = textContentElement->lengthAdjustCurrentValue(); - desiredTextLength = textContentElement->specifiedTextLength().value(lengthContext); + lengthAdjust = textContentElement->lengthAdjust()->currentValue()->enumValue(); + if (textContentElement->textLengthIsSpecifiedByUser()) + desiredTextLength = textContentElement->textLength()->currentValue()->value(lengthContext); + else + desiredTextLength = 0; } if (!desiredTextLength) @@ -222,7 +227,8 @@ void SVGTextLayoutEngine::beginTextPathLayout(RenderObject* object, SVGTextLayou void SVGTextLayoutEngine::endTextPathLayout() { m_inPathLayout = false; - m_textPath = Path(); + delete m_textPathCalculator; + m_textPathCalculator = 0; m_textPathLength = 0; m_textPathStartOffset = 0; m_textPathCurrentOffset = 0; @@ -234,18 +240,17 @@ void SVGTextLayoutEngine::layoutInlineTextBox(SVGInlineTextBox* textBox) { ASSERT(textBox); - RenderSVGInlineText* text = toRenderSVGInlineText(textBox->textRenderer()); - ASSERT(text); - ASSERT(text->parent()); - ASSERT(text->parent()->node()); - ASSERT(text->parent()->node()->isSVGElement()); + RenderSVGInlineText& text = toRenderSVGInlineText(textBox->textRenderer()); + ASSERT(text.parent()); + ASSERT(text.parent()->node()); + ASSERT(text.parent()->node()->isSVGElement()); - const RenderStyle* style = text->style(); + const RenderStyle* style = text.style(); ASSERT(style); textBox->clearTextFragments(); m_isVerticalText = style->svgStyle()->isVerticalWritingMode(); - layoutTextOnLineOrPath(textBox, text, style); + layoutTextOnLineOrPath(textBox, &text, style); if (m_inPathLayout) { m_pathLayoutBoxes.append(textBox); @@ -421,7 +426,7 @@ void SVGTextLayoutEngine::advanceToNextVisualCharacter(const SVGTextMetrics& vis void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, RenderSVGInlineText* text, const RenderStyle* style) { - if (m_inPathLayout && m_textPath.isEmpty()) + if (m_inPathLayout && !m_textPathCalculator) return; SVGElement* lengthContext = toSVGElement(text->parent()->node()); @@ -440,7 +445,7 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend const Font& font = style->font(); - SVGTextLayoutEngineSpacing spacingLayout(font); + SVGTextLayoutEngineSpacing spacingLayout(font, style->effectiveZoom()); SVGTextLayoutEngineBaseline baselineLayout(font); bool didStartTextFragment = false; @@ -505,8 +510,8 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend // Calculate SVG Fonts kerning, if needed. float kerning = spacingLayout.calculateSVGKerning(m_isVerticalText, visualMetrics.glyph()); - // Calculate CSS 'kerning', 'letter-spacing' and 'word-spacing' for next character, if needed. - float spacing = spacingLayout.calculateCSSKerningAndSpacing(svgStyle, lengthContext, currentCharacter); + // Calculate CSS 'letter-spacing' and 'word-spacing' for next character, if needed. + float spacing = spacingLayout.calculateCSSSpacing(currentCharacter); float textPathOffset = 0; if (m_inPathLayout) { @@ -552,14 +557,11 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend if (textPathOffset > m_textPathLength) break; - bool ok = false; - FloatPoint point = m_textPath.pointAtLength(textPathOffset, ok); - ASSERT(ok); - + FloatPoint point; + bool ok = m_textPathCalculator->pointAndNormalAtLength(textPathOffset, point, angle); + ASSERT_UNUSED(ok, ok); x = point.x(); y = point.y(); - angle = m_textPath.normalAngleAtLength(textPathOffset, ok); - ASSERT(ok); // For vertical text on path, the actual angle has to be rotated 90 degrees anti-clockwise, not the orientation angle! if (m_isVerticalText) diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngine.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngine.h index 3ae5fa09087..b3c91a445b2 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngine.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngine.h @@ -32,9 +32,7 @@ namespace WebCore { class RenderObject; class RenderStyle; class RenderSVGInlineText; -class SVGElement; class SVGInlineTextBox; -class SVGRenderStyle; // SVGTextLayoutEngine performs the second layout phase for SVG text. // @@ -96,7 +94,7 @@ private: bool m_inPathLayout; // Text on path layout - Path m_textPath; + Path::PositionCalculator* m_textPathCalculator; float m_textPathLength; float m_textPathStartOffset; float m_textPathCurrentOffset; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineBaseline.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineBaseline.cpp index 3825b4b1220..95c3beb137c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineBaseline.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineBaseline.cpp @@ -38,12 +38,12 @@ SVGTextLayoutEngineBaseline::SVGTextLayoutEngineBaseline(const Font& font) float SVGTextLayoutEngineBaseline::calculateBaselineShift(const SVGRenderStyle* style, SVGElement* contextElement) const { if (style->baselineShift() == BS_LENGTH) { - SVGLength baselineShiftValueLength = style->baselineShiftValue(); - if (baselineShiftValueLength.unitType() == LengthTypePercentage) - return baselineShiftValueLength.valueAsPercentage() * m_font.pixelSize(); + RefPtr<SVGLength> baselineShiftValueLength = style->baselineShiftValue(); + if (baselineShiftValueLength->unitType() == LengthTypePercentage) + return baselineShiftValueLength->valueAsPercentage() * m_font.fontDescription().computedPixelSize(); SVGLengthContext lengthContext(contextElement); - return baselineShiftValueLength.value(lengthContext); + return baselineShiftValueLength->value(lengthContext); } switch (style->baselineShift()) { @@ -160,7 +160,7 @@ float SVGTextLayoutEngineBaseline::calculateGlyphOrientationAngle(bool isVertica case GO_AUTO: { // Spec: Fullwidth ideographic and fullwidth Latin text will be set with a glyph-orientation of 0-degrees. // Text which is not fullwidth will be set with a glyph-orientation of 90-degrees. - unsigned int unicodeRange = findCharUnicodeRange(character); + unsigned unicodeRange = findCharUnicodeRange(character); if (unicodeRange == cRangeSetLatin || unicodeRange == cRangeArabic) return 90; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineSpacing.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineSpacing.cpp index 6f68e475f1e..e93bb48b41a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineSpacing.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineSpacing.cpp @@ -21,8 +21,8 @@ #include "core/rendering/svg/SVGTextLayoutEngineSpacing.h" -#include "core/rendering/style/SVGRenderStyle.h" #include "core/svg/SVGLengthContext.h" +#include "platform/fonts/Character.h" #include "platform/fonts/Font.h" #if ENABLE(SVG_FONTS) @@ -33,18 +33,23 @@ namespace WebCore { -SVGTextLayoutEngineSpacing::SVGTextLayoutEngineSpacing(const Font& font) +SVGTextLayoutEngineSpacing::SVGTextLayoutEngineSpacing(const Font& font, float effectiveZoom) : m_font(font) , m_lastCharacter(0) + , m_effectiveZoom(effectiveZoom) +#if ENABLE(SVG_FONTS) + , m_lastGlyph(0) +#endif { + ASSERT(m_effectiveZoom); } -float SVGTextLayoutEngineSpacing::calculateSVGKerning(bool isVerticalText, const SVGTextMetrics::Glyph& currentGlyph) +float SVGTextLayoutEngineSpacing::calculateSVGKerning(bool isVerticalText, Glyph currentGlyph) { #if ENABLE(SVG_FONTS) const SimpleFontData* fontData = m_font.primaryFont(); if (!fontData->isSVGFont()) { - m_lastGlyph.isValid = false; + m_lastGlyph = 0; return 0; } @@ -58,50 +63,44 @@ float SVGTextLayoutEngineSpacing::calculateSVGKerning(bool isVerticalText, const SVGFontElement* svgFont = svgFontFace->associatedFontElement(); if (!svgFont) { - m_lastGlyph.isValid = false; + m_lastGlyph = 0; return 0; } float kerning = 0; - if (m_lastGlyph.isValid) { + if (m_lastGlyph) { if (isVerticalText) - kerning = svgFont->verticalKerningForPairOfStringsAndGlyphs(m_lastGlyph.unicodeString, m_lastGlyph.name, currentGlyph.unicodeString, currentGlyph.name); + kerning = svgFont->verticalKerningForPairOfGlyphs(m_lastGlyph, currentGlyph); else - kerning = svgFont->horizontalKerningForPairOfStringsAndGlyphs(m_lastGlyph.unicodeString, m_lastGlyph.name, currentGlyph.unicodeString, currentGlyph.name); + kerning = svgFont->horizontalKerningForPairOfGlyphs(m_lastGlyph, currentGlyph); + + kerning *= m_font.fontDescription().computedSize() / m_font.fontMetrics().unitsPerEm(); } m_lastGlyph = currentGlyph; - m_lastGlyph.isValid = true; - kerning *= m_font.size() / m_font.fontMetrics().unitsPerEm(); return kerning; #else - return false; + return 0; #endif } -float SVGTextLayoutEngineSpacing::calculateCSSKerningAndSpacing(const SVGRenderStyle* style, SVGElement* contextElement, UChar currentCharacter) +float SVGTextLayoutEngineSpacing::calculateCSSSpacing(UChar currentCharacter) { - float kerning = 0; - SVGLength kerningLength = style->kerning(); - if (kerningLength.unitType() == LengthTypePercentage) - kerning = kerningLength.valueAsPercentage() * m_font.pixelSize(); - else { - SVGLengthContext lengthContext(contextElement); - kerning = kerningLength.value(lengthContext); - } - UChar lastCharacter = m_lastCharacter; m_lastCharacter = currentCharacter; - if (!kerning && !m_font.letterSpacing() && !m_font.wordSpacing()) + if (!m_font.fontDescription().letterSpacing() && !m_font.fontDescription().wordSpacing()) return 0; - float spacing = m_font.letterSpacing() + kerning; - if (currentCharacter && lastCharacter && m_font.wordSpacing()) { - if (Font::treatAsSpace(currentCharacter) && !Font::treatAsSpace(lastCharacter)) - spacing += m_font.wordSpacing(); + float spacing = m_font.fontDescription().letterSpacing(); + if (currentCharacter && lastCharacter && m_font.fontDescription().wordSpacing()) { + if (Character::treatAsSpace(currentCharacter) && !Character::treatAsSpace(lastCharacter)) + spacing += m_font.fontDescription().wordSpacing(); } + if (m_effectiveZoom != 1) + spacing = spacing / m_effectiveZoom; + return spacing; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineSpacing.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineSpacing.h index 5cc8bec5533..8618e246dd4 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineSpacing.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineSpacing.h @@ -25,24 +25,23 @@ namespace WebCore { class Font; -class SVGRenderStyle; -class SVGElement; -// Helper class used by SVGTextLayoutEngine to handle 'kerning' / 'letter-spacing' and 'word-spacing'. +// Helper class used by SVGTextLayoutEngine to handle 'letter-spacing' and 'word-spacing'. class SVGTextLayoutEngineSpacing { WTF_MAKE_NONCOPYABLE(SVGTextLayoutEngineSpacing); public: - SVGTextLayoutEngineSpacing(const Font&); + SVGTextLayoutEngineSpacing(const Font&, float effectiveZoom); - float calculateSVGKerning(bool isVerticalText, const SVGTextMetrics::Glyph& currentGlyph); - float calculateCSSKerningAndSpacing(const SVGRenderStyle*, SVGElement* lengthContext, UChar currentCharacter); + float calculateSVGKerning(bool isVerticalText, Glyph currentGlyph); + float calculateCSSSpacing(UChar currentCharacter); private: const Font& m_font; UChar m_lastCharacter; + float m_effectiveZoom; #if ENABLE(SVG_FONTS) - SVGTextMetrics::Glyph m_lastGlyph; + Glyph m_lastGlyph; #endif }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetrics.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetrics.cpp index 26c82dbec27..3ab52797f77 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetrics.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetrics.cpp @@ -30,6 +30,7 @@ SVGTextMetrics::SVGTextMetrics() : m_width(0) , m_height(0) , m_length(0) + , m_glyph(0) { } @@ -37,6 +38,7 @@ SVGTextMetrics::SVGTextMetrics(SVGTextMetrics::MetricsType) : m_width(0) , m_height(0) , m_length(1) + , m_glyph(0) { } @@ -51,18 +53,21 @@ SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* textRenderer, const TextRun& int length = 0; // Calculate width/height using the scaled font, divide this result by the scalingFactor afterwards. - m_width = scaledFont.width(run, length, m_glyph.name) / scalingFactor; + m_width = scaledFont.width(run, length, m_glyph) / scalingFactor; m_height = scaledFont.fontMetrics().floatHeight() / scalingFactor; - m_glyph.unicodeString = run.is8Bit() ? String(run.characters8(), length) : String(run.characters16(), length); - m_glyph.isValid = true; - ASSERT(length >= 0); m_length = static_cast<unsigned>(length); } TextRun SVGTextMetrics::constructTextRun(RenderSVGInlineText* text, unsigned position, unsigned length) { + ASSERT(text->style()); + return constructTextRun(text, position, length, text->style()->direction()); +} + +TextRun SVGTextMetrics::constructTextRun(RenderSVGInlineText* text, unsigned position, unsigned length, TextDirection textDirection) +{ RenderStyle* style = text->style(); ASSERT(style); @@ -71,7 +76,7 @@ TextRun SVGTextMetrics::constructTextRun(RenderSVGInlineText* text, unsigned pos , 0 // xPos, only relevant with allowTabs=true , 0 // padding, only relevant for justified text, not relevant for SVG , TextRun::AllowTrailingExpansion - , style->direction() + , textDirection , isOverride(style->unicodeBidi()) /* directionalOverride */); if (length) { @@ -95,13 +100,19 @@ TextRun SVGTextMetrics::constructTextRun(RenderSVGInlineText* text, unsigned pos return run; } +SVGTextMetrics SVGTextMetrics::measureCharacterRange(RenderSVGInlineText* text, unsigned position, unsigned length, TextDirection textDirection) +{ + ASSERT(text); + return SVGTextMetrics(text, constructTextRun(text, position, length, textDirection)); +} + SVGTextMetrics SVGTextMetrics::measureCharacterRange(RenderSVGInlineText* text, unsigned position, unsigned length) { ASSERT(text); return SVGTextMetrics(text, constructTextRun(text, position, length)); } -SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* text, unsigned position, unsigned length, float width, const String& glyphName) +SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* text, unsigned position, unsigned length, float width, Glyph glyphNameGlyphId) { ASSERT(text); @@ -111,11 +122,7 @@ SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* text, unsigned position, uns m_width = width / scalingFactor; m_height = text->scaledFont().fontMetrics().floatHeight() / scalingFactor; - if (needsContext) { - m_glyph.isValid = true; - m_glyph.unicodeString = text->substring(position, length); - m_glyph.name = glyphName; - } + m_glyph = needsContext ? glyphNameGlyphId : 0; m_length = length; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetrics.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetrics.h index 362933997ed..3c04901e2cf 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetrics.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetrics.h @@ -20,12 +20,13 @@ #ifndef SVGTextMetrics_h #define SVGTextMetrics_h +#include "platform/fonts/Glyph.h" +#include "platform/text/TextDirection.h" #include "wtf/text/WTFString.h" namespace WebCore { class RenderSVGInlineText; -class SVGTextLayoutAttributes; class TextRun; class SVGTextMetrics { @@ -36,12 +37,16 @@ public: SVGTextMetrics(); SVGTextMetrics(MetricsType); - SVGTextMetrics(RenderSVGInlineText*, unsigned position, unsigned length, float width, const String& glyphName); + SVGTextMetrics(RenderSVGInlineText*, unsigned position, unsigned length, float width, Glyph glyphNameGlyphId); + // FIXME: Migrate away from these to the two below. static SVGTextMetrics measureCharacterRange(RenderSVGInlineText*, unsigned position, unsigned length); static TextRun constructTextRun(RenderSVGInlineText*, unsigned position, unsigned length); - bool isEmpty() const { return !m_width && !m_height && !m_glyph.isValid && m_length == 1; } + static SVGTextMetrics measureCharacterRange(RenderSVGInlineText*, unsigned position, unsigned length, TextDirection); + static TextRun constructTextRun(RenderSVGInlineText*, unsigned position, unsigned length, TextDirection); + + bool isEmpty() const { return !m_width && !m_height && m_length <= 1; } float width() const { return m_width; } void setWidth(float width) { m_width = width; } @@ -49,19 +54,8 @@ public: float height() const { return m_height; } unsigned length() const { return m_length; } - struct Glyph { - Glyph() - : isValid(false) - { - } - - bool isValid; - String name; - String unicodeString; - }; - // Only useful when measuring individual characters, to lookup ligatures. - const Glyph& glyph() const { return m_glyph; } + Glyph glyph() const { return m_glyph; } private: SVGTextMetrics(RenderSVGInlineText*, const TextRun&); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetricsBuilder.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetricsBuilder.cpp index 46a27979e9d..eaaa9361d19 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetricsBuilder.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetricsBuilder.cpp @@ -21,186 +21,238 @@ #include "core/rendering/svg/SVGTextMetricsBuilder.h" +#include "core/rendering/svg/RenderSVGInline.h" #include "core/rendering/svg/RenderSVGInlineText.h" #include "core/rendering/svg/RenderSVGText.h" +#include "core/rendering/svg/SVGTextMetrics.h" +#include "platform/fonts/GlyphBuffer.h" +#include "platform/fonts/WidthIterator.h" +#include "platform/text/BidiCharacterRun.h" +#include "platform/text/BidiResolver.h" +#include "platform/text/TextDirection.h" +#include "platform/text/TextPath.h" +#include "platform/text/TextRun.h" +#include "platform/text/TextRunIterator.h" +#include "wtf/Vector.h" namespace WebCore { -SVGTextMetricsBuilder::SVGTextMetricsBuilder() - : m_text(0) - , m_run(static_cast<const UChar*>(0), 0) - , m_textPosition(0) +class SVGTextMetricsCalculator { +public: + SVGTextMetricsCalculator(RenderSVGInlineText*); + ~SVGTextMetricsCalculator(); + + SVGTextMetrics computeMetricsForCharacter(unsigned textPosition); + unsigned textLength() const { return static_cast<unsigned>(m_run.charactersLength()); } + + bool characterStartsSurrogatePair(unsigned textPosition) const + { + return U16_IS_LEAD(m_run[textPosition]) && textPosition + 1 < textLength() && U16_IS_TRAIL(m_run[textPosition + 1]); + } + bool characterIsWhiteSpace(unsigned textPosition) const + { + return m_run[textPosition] == ' '; + } + +private: + void setupBidiRuns(); + SVGTextMetrics computeMetricsForCharacterSimple(unsigned textPosition); + SVGTextMetrics computeMetricsForCharacterComplex(unsigned textPosition); + + RenderSVGInlineText* m_text; + BidiCharacterRun* m_bidiRun; + TextRun m_run; + BidiResolver<TextRunIterator, BidiCharacterRun> m_bidiResolver; + bool m_isComplexText; + float m_totalWidth; + TextDirection m_textDirection; + + // Simple text only. + OwnPtr<WidthIterator> m_simpleWidthIterator; +}; + +SVGTextMetricsCalculator::SVGTextMetricsCalculator(RenderSVGInlineText* text) + : m_text(text) + , m_bidiRun(0) + , m_run(SVGTextMetrics::constructTextRun(text, 0, text->textLength())) , m_isComplexText(false) , m_totalWidth(0) { + const Font& scaledFont = text->scaledFont(); + CodePath codePath = scaledFont.codePath(m_run); + m_isComplexText = codePath == ComplexPath; + m_run.setCharacterScanForCodePath(!m_isComplexText); + + if (!m_isComplexText) + m_simpleWidthIterator = adoptPtr(new WidthIterator(&scaledFont, m_run)); + else + setupBidiRuns(); } -inline bool SVGTextMetricsBuilder::currentCharacterStartsSurrogatePair() const +SVGTextMetricsCalculator::~SVGTextMetricsCalculator() { - return U16_IS_LEAD(m_run[m_textPosition]) && int(m_textPosition + 1) < m_run.charactersLength() && U16_IS_TRAIL(m_run[m_textPosition + 1]); + if (m_bidiRun) + m_bidiResolver.runs().deleteRuns(); } -bool SVGTextMetricsBuilder::advance() +void SVGTextMetricsCalculator::setupBidiRuns() { - m_textPosition += m_currentMetrics.length(); - if (int(m_textPosition) >= m_run.charactersLength()) - return false; - - if (m_isComplexText) - advanceComplexText(); - else - advanceSimpleText(); + RenderStyle* style = m_text->style(); + m_textDirection = style->direction(); + if (isOverride(style->unicodeBidi())) + return; - return m_currentMetrics.length() > 0; + BidiStatus status(LTR, false); + status.last = status.lastStrong = WTF::Unicode::OtherNeutral; + m_bidiResolver.setStatus(status); + m_bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&m_run, 0)); + const bool hardLineBreak = false; + const bool reorderRuns = false; + m_bidiResolver.createBidiRunsForLine(TextRunIterator(&m_run, m_run.length()), NoVisualOverride, hardLineBreak, reorderRuns); + BidiRunList<BidiCharacterRun>& bidiRuns = m_bidiResolver.runs(); + m_bidiRun = bidiRuns.firstRun(); } -void SVGTextMetricsBuilder::advanceSimpleText() +SVGTextMetrics SVGTextMetricsCalculator::computeMetricsForCharacterSimple(unsigned textPosition) { GlyphBuffer glyphBuffer; - unsigned metricsLength = m_simpleWidthIterator->advance(m_textPosition + 1, &glyphBuffer); - if (!metricsLength) { - m_currentMetrics = SVGTextMetrics(); - return; - } + unsigned metricsLength = m_simpleWidthIterator->advance(textPosition + 1, &glyphBuffer); + if (!metricsLength) + return SVGTextMetrics(); float currentWidth = m_simpleWidthIterator->runWidthSoFar() - m_totalWidth; m_totalWidth = m_simpleWidthIterator->runWidthSoFar(); -#if ENABLE(SVG_FONTS) - m_currentMetrics = SVGTextMetrics(m_text, m_textPosition, metricsLength, currentWidth, m_simpleWidthIterator->lastGlyphName()); -#else - m_currentMetrics = SVGTextMetrics(m_text, m_textPosition, metricsLength, currentWidth, emptyString()); -#endif + Glyph glyphId = glyphBuffer.glyphAt(0); + return SVGTextMetrics(m_text, textPosition, metricsLength, currentWidth, glyphId); } -void SVGTextMetricsBuilder::advanceComplexText() +SVGTextMetrics SVGTextMetricsCalculator::computeMetricsForCharacterComplex(unsigned textPosition) { - unsigned metricsLength = currentCharacterStartsSurrogatePair() ? 2 : 1; - m_currentMetrics = SVGTextMetrics::measureCharacterRange(m_text, m_textPosition, metricsLength); - m_complexStartToCurrentMetrics = SVGTextMetrics::measureCharacterRange(m_text, 0, m_textPosition + metricsLength); - ASSERT(m_currentMetrics.length() == metricsLength); + unsigned metricsLength = characterStartsSurrogatePair(textPosition) ? 2 : 1; + SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(m_text, textPosition, metricsLength, m_textDirection); + ASSERT(metrics.length() == metricsLength); + unsigned startPosition = m_bidiRun ? m_bidiRun->start() : 0; + ASSERT(startPosition <= textPosition); + SVGTextMetrics complexStartToCurrentMetrics = SVGTextMetrics::measureCharacterRange(m_text, startPosition, textPosition - startPosition + metricsLength, m_textDirection); // Frequent case for Arabic text: when measuring a single character the arabic isolated form is taken // when rendering the glyph "in context" (with it's surrounding characters) it changes due to shaping. // So whenever currentWidth != currentMetrics.width(), we are processing a text run whose length is // not equal to the sum of the individual lengths of the glyphs, when measuring them isolated. - float currentWidth = m_complexStartToCurrentMetrics.width() - m_totalWidth; - if (currentWidth != m_currentMetrics.width()) - m_currentMetrics.setWidth(currentWidth); + float currentWidth = complexStartToCurrentMetrics.width() - m_totalWidth; + if (currentWidth != metrics.width()) + metrics.setWidth(currentWidth); - m_totalWidth = m_complexStartToCurrentMetrics.width(); + m_totalWidth = complexStartToCurrentMetrics.width(); + return metrics; } -void SVGTextMetricsBuilder::initializeMeasurementWithTextRenderer(RenderSVGInlineText* text) +SVGTextMetrics SVGTextMetricsCalculator::computeMetricsForCharacter(unsigned textPosition) { - m_text = text; - m_textPosition = 0; - m_currentMetrics = SVGTextMetrics(); - m_complexStartToCurrentMetrics = SVGTextMetrics(); - m_totalWidth = 0; - - const Font& scaledFont = text->scaledFont(); - m_run = SVGTextMetrics::constructTextRun(text, 0, text->textLength()); - m_isComplexText = scaledFont.codePath(m_run) == Font::Complex; + if (m_bidiRun) { + if (textPosition >= static_cast<unsigned>(m_bidiRun->stop())) { + m_bidiRun = m_bidiRun->next(); + // New BiDi run means new reference position for measurements, so reset |m_totalWidth|. + m_totalWidth = 0; + } + ASSERT(m_bidiRun); + ASSERT(static_cast<int>(textPosition) < m_bidiRun->stop()); + m_textDirection = m_bidiRun->direction(); + } if (m_isComplexText) - m_simpleWidthIterator.clear(); - else - m_simpleWidthIterator = adoptPtr(new WidthIterator(&scaledFont, m_run)); + return computeMetricsForCharacterComplex(textPosition); + + return computeMetricsForCharacterSimple(textPosition); } struct MeasureTextData { MeasureTextData(SVGCharacterDataMap* characterDataMap) : allCharactersMap(characterDataMap) - , hasLastCharacter(false) - , lastCharacter(0) - , processRenderer(false) + , lastCharacterWasWhiteSpace(true) , valueListPosition(0) - , skippedCharacters(0) { } SVGCharacterDataMap* allCharactersMap; - bool hasLastCharacter; - UChar lastCharacter; - bool processRenderer; + bool lastCharacterWasWhiteSpace; unsigned valueListPosition; - unsigned skippedCharacters; }; -void SVGTextMetricsBuilder::measureTextRenderer(RenderSVGInlineText* text, MeasureTextData* data) +static void measureTextRenderer(RenderSVGInlineText* text, MeasureTextData* data, bool processRenderer) { ASSERT(text); SVGTextLayoutAttributes* attributes = text->layoutAttributes(); Vector<SVGTextMetrics>* textMetricsValues = &attributes->textMetricsValues(); - if (data->processRenderer) { + if (processRenderer) { if (data->allCharactersMap) attributes->clear(); else textMetricsValues->clear(); } - initializeMeasurementWithTextRenderer(text); + SVGTextMetricsCalculator calculator(text); bool preserveWhiteSpace = text->style()->whiteSpace() == PRE; - int surrogatePairCharacters = 0; - - while (advance()) { - UChar currentCharacter = m_run[m_textPosition]; - if (currentCharacter == ' ' && !preserveWhiteSpace && (!data->hasLastCharacter || data->lastCharacter == ' ')) { - if (data->processRenderer) + unsigned surrogatePairCharacters = 0; + unsigned skippedCharacters = 0; + unsigned textPosition = 0; + unsigned textLength = calculator.textLength(); + + SVGTextMetrics currentMetrics; + for (; textPosition < textLength; textPosition += currentMetrics.length()) { + currentMetrics = calculator.computeMetricsForCharacter(textPosition); + if (!currentMetrics.length()) + break; + + bool characterIsWhiteSpace = calculator.characterIsWhiteSpace(textPosition); + if (characterIsWhiteSpace && !preserveWhiteSpace && data->lastCharacterWasWhiteSpace) { + if (processRenderer) textMetricsValues->append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics)); if (data->allCharactersMap) - data->skippedCharacters += m_currentMetrics.length(); + skippedCharacters += currentMetrics.length(); continue; } - if (data->processRenderer) { + if (processRenderer) { if (data->allCharactersMap) { - const SVGCharacterDataMap::const_iterator it = data->allCharactersMap->find(data->valueListPosition + m_textPosition - data->skippedCharacters - surrogatePairCharacters + 1); + const SVGCharacterDataMap::const_iterator it = data->allCharactersMap->find(data->valueListPosition + textPosition - skippedCharacters - surrogatePairCharacters + 1); if (it != data->allCharactersMap->end()) - attributes->characterDataMap().set(m_textPosition + 1, it->value); + attributes->characterDataMap().set(textPosition + 1, it->value); } - textMetricsValues->append(m_currentMetrics); + textMetricsValues->append(currentMetrics); } - if (data->allCharactersMap && currentCharacterStartsSurrogatePair()) + if (data->allCharactersMap && calculator.characterStartsSurrogatePair(textPosition)) surrogatePairCharacters++; - data->hasLastCharacter = true; - data->lastCharacter = currentCharacter; + data->lastCharacterWasWhiteSpace = characterIsWhiteSpace; } if (!data->allCharactersMap) return; - data->valueListPosition += m_textPosition - data->skippedCharacters; - data->skippedCharacters = 0; + data->valueListPosition += textPosition - skippedCharacters; } -void SVGTextMetricsBuilder::walkTree(RenderObject* start, RenderSVGInlineText* stopAtLeaf, MeasureTextData* data) +static void walkTree(RenderSVGText* start, RenderSVGInlineText* stopAtLeaf, MeasureTextData* data) { - for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { + RenderObject* child = start->firstChild(); + while (child) { if (child->isSVGInlineText()) { RenderSVGInlineText* text = toRenderSVGInlineText(child); - if (stopAtLeaf && stopAtLeaf != text) { - data->processRenderer = false; - measureTextRenderer(text, data); + measureTextRenderer(text, data, !stopAtLeaf || stopAtLeaf == text); + if (stopAtLeaf && stopAtLeaf == text) + return; + } else if (child->isSVGInline()) { + // Visit children of text content elements. + if (RenderObject* inlineChild = toRenderSVGInline(child)->firstChild()) { + child = inlineChild; continue; } - - data->processRenderer = true; - measureTextRenderer(text, data); - if (stopAtLeaf) - return; - - continue; } - - if (!child->isSVGInline()) - continue; - - walkTree(child, stopAtLeaf, data); + child = child->nextInPreOrderAfterChildren(start); } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetricsBuilder.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetricsBuilder.h index 076b052283a..bf0c5c77095 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetricsBuilder.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetricsBuilder.h @@ -21,48 +21,18 @@ #define SVGTextMetricsBuilder_h #include "core/rendering/svg/SVGTextLayoutAttributes.h" -#include "core/rendering/svg/SVGTextMetrics.h" -#include "platform/fonts/WidthIterator.h" -#include "platform/text/TextRun.h" -#include "wtf/Vector.h" namespace WebCore { -class RenderObject; class RenderSVGInlineText; class RenderSVGText; -struct MeasureTextData; -class SVGTextMetricsBuilder { - WTF_MAKE_NONCOPYABLE(SVGTextMetricsBuilder); -public: - SVGTextMetricsBuilder(); - void measureTextRenderer(RenderSVGInlineText*); - void buildMetricsAndLayoutAttributes(RenderSVGText*, RenderSVGInlineText* stopAtLeaf, SVGCharacterDataMap& allCharactersMap); +namespace SVGTextMetricsBuilder { -private: - bool advance(); - void advanceSimpleText(); - void advanceComplexText(); - bool currentCharacterStartsSurrogatePair() const; +void measureTextRenderer(RenderSVGInlineText*); +void buildMetricsAndLayoutAttributes(RenderSVGText*, RenderSVGInlineText* stopAtLeaf, SVGCharacterDataMap& allCharactersMap); - void initializeMeasurementWithTextRenderer(RenderSVGInlineText*); - void walkTree(RenderObject*, RenderSVGInlineText* stopAtLeaf, MeasureTextData*); - void measureTextRenderer(RenderSVGInlineText*, MeasureTextData*); - - RenderSVGInlineText* m_text; - TextRun m_run; - unsigned m_textPosition; - bool m_isComplexText; - SVGTextMetrics m_currentMetrics; - float m_totalWidth; - - // Simple text only. - OwnPtr<WidthIterator> m_simpleWidthIterator; - - // Complex text only. - SVGTextMetrics m_complexStartToCurrentMetrics; -}; +} // namespace SVGTextMetricsBuilder } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextQuery.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextQuery.cpp index 4bf2a3c3da7..f5ead0d4366 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextQuery.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextQuery.cpp @@ -90,7 +90,7 @@ void SVGTextQuery::collectTextBoxesInFlowBox(InlineFlowBox* flowBox) for (InlineBox* child = flowBox->firstChild(); child; child = child->nextOnLine()) { if (child->isInlineFlowBox()) { // Skip generated content. - if (!child->renderer()->node()) + if (!child->renderer().node()) continue; collectTextBoxesInFlowBox(toInlineFlowBox(child)); @@ -112,8 +112,7 @@ bool SVGTextQuery::executeQuery(Data* queryData, ProcessTextFragmentCallback fra // Loop over all text boxes for (unsigned textBoxPosition = 0; textBoxPosition < textBoxCount; ++textBoxPosition) { queryData->textBox = m_textBoxes.at(textBoxPosition); - queryData->textRenderer = toRenderSVGInlineText(queryData->textBox->textRenderer()); - ASSERT(queryData->textRenderer); + queryData->textRenderer = &toRenderSVGInlineText(queryData->textBox->textRenderer()); ASSERT(queryData->textRenderer->style()); ASSERT(queryData->textRenderer->style()->svgStyle()); @@ -142,7 +141,9 @@ bool SVGTextQuery::mapStartEndPositionsIntoFragmentCoordinates(Data* queryData, startPosition -= queryData->processedCharacters; endPosition -= queryData->processedCharacters; - if (startPosition >= endPosition || startPosition < 0 || endPosition < 0) + startPosition = max(0, startPosition); + + if (startPosition >= endPosition) return false; modifyStartEndPositionsRespectingLigatures(queryData, startPosition, endPosition); @@ -215,15 +216,11 @@ void SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, i return; if (lastPositionOffset != -1 && lastPositionOffset - positionOffset > 1) { - if (alterStartPosition && startPosition > lastPositionOffset && startPosition < static_cast<int>(positionOffset)) { + if (alterStartPosition && startPosition > lastPositionOffset && startPosition < static_cast<int>(positionOffset)) startPosition = lastPositionOffset; - alterStartPosition = false; - } - if (alterEndPosition && endPosition > lastPositionOffset && endPosition < static_cast<int>(positionOffset)) { + if (alterEndPosition && endPosition > lastPositionOffset && endPosition < static_cast<int>(positionOffset)) endPosition = positionOffset; - alterEndPosition = false; - } } } @@ -480,8 +477,6 @@ static inline void calculateGlyphBoundaries(SVGTextQuery::Data* queryData, const AffineTransform fragmentTransform; fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength); - if (fragmentTransform.isIdentity()) - return; extent = fragmentTransform.mapRect(extent); } @@ -499,10 +494,10 @@ bool SVGTextQuery::extentOfCharacterCallback(Data* queryData, const SVGTextFragm return true; } -SVGRect SVGTextQuery::extentOfCharacter(unsigned position) const +FloatRect SVGTextQuery::extentOfCharacter(unsigned position) const { if (m_textBoxes.isEmpty()) - return SVGRect(); + return FloatRect(); ExtentOfCharacterData data(position); executeQuery(&data, &SVGTextQuery::extentOfCharacterCallback); @@ -540,7 +535,7 @@ bool SVGTextQuery::characterNumberAtPositionCallback(Data* queryData, const SVGT return false; } -int SVGTextQuery::characterNumberAtPosition(const SVGPoint& position) const +int SVGTextQuery::characterNumberAtPosition(const FloatPoint& position) const { if (m_textBoxes.isEmpty()) return -1; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextQuery.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextQuery.h index 652d751af70..a5601f74d30 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextQuery.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextQuery.h @@ -21,8 +21,8 @@ #define SVGTextQuery_h #include "core/rendering/svg/SVGTextFragment.h" -#include "core/svg/SVGPoint.h" -#include "core/svg/SVGRect.h" +#include "platform/geometry/FloatPoint.h" +#include "platform/geometry/FloatRect.h" #include "wtf/Vector.h" namespace WebCore { @@ -41,8 +41,8 @@ public: FloatPoint startPositionOfCharacter(unsigned position) const; FloatPoint endPositionOfCharacter(unsigned position) const; float rotationOfCharacter(unsigned position) const; - SVGRect extentOfCharacter(unsigned position) const; - int characterNumberAtPosition(const SVGPoint&) const; + FloatRect extentOfCharacter(unsigned position) const; + int characterNumberAtPosition(const FloatPoint&) const; // Public helper struct. Private classes in SVGTextQuery inherit from it. struct Data; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextRunRenderingContext.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextRunRenderingContext.cpp index c48c91e2486..7765117cd28 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextRunRenderingContext.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextRunRenderingContext.cpp @@ -23,7 +23,6 @@ #if ENABLE(SVG_FONTS) #include "core/rendering/svg/SVGTextRunRenderingContext.h" -#include "SVGNames.h" #include "core/rendering/RenderObject.h" #include "core/rendering/svg/RenderSVGInlineText.h" #include "core/rendering/svg/RenderSVGResourceSolidColor.h" @@ -46,6 +45,10 @@ static inline const SVGFontData* svgFontAndFontFaceElementForFontData(const Simp RefPtr<CustomFontData> customFontData = fontData->customFontData(); const SVGFontData* svgFontData = static_cast<const SVGFontData*>(customFontData.get()); + // FIXME crbug.com/359380 : The current editing impl references the font after the svg font nodes are removed. + if (svgFontData->shouldSkipDrawing()) + return 0; + fontFace = svgFontData->svgFontFaceElement(); ASSERT(fontFace); @@ -73,12 +76,12 @@ static inline RenderSVGResource* activePaintingResourceFromRun(const TextRun& ru return 0; } -float SVGTextRunRenderingContext::floatWidthUsingSVGFont(const Font& font, const TextRun& run, int& charsConsumed, String& glyphName) const +float SVGTextRunRenderingContext::floatWidthUsingSVGFont(const Font& font, const TextRun& run, int& charsConsumed, Glyph& glyphId) const { WidthIterator it(&font, run); GlyphBuffer glyphBuffer; charsConsumed += it.advance(run.length(), &glyphBuffer); - glyphName = it.lastGlyphName(); + glyphId = !glyphBuffer.isEmpty() ? glyphBuffer.glyphAt(0) : 0; return it.runWidthSoFar(); } @@ -119,14 +122,17 @@ void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const T glyphOrigin.setX(svgFontData->horizontalOriginX() * scale); glyphOrigin.setY(svgFontData->horizontalOriginY() * scale); + unsigned short resourceMode = context->textDrawingMode() == TextModeStroke ? ApplyToStrokeMode : ApplyToFillMode; + // From a resource perspective this ought to be treated as "text mode". + resourceMode |= ApplyToTextMode; + FloatPoint currentPoint = point; - RenderSVGResourceMode resourceMode = context->textDrawingMode() == TextModeStroke ? ApplyToStrokeMode : ApplyToFillMode; for (int i = 0; i < numGlyphs; ++i) { Glyph glyph = glyphBuffer.glyphAt(from + i); if (!glyph) continue; - float advance = glyphBuffer.advanceAt(from + i); + float advance = glyphBuffer.advanceAt(from + i).width(); SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph); ASSERT(!svgGlyph.isPartOfLigature); ASSERT(svgGlyph.tableEntry == glyph); @@ -198,7 +204,7 @@ GlyphData SVGTextRunRenderingContext::glyphDataForCharacter(const Font& font, co RenderObject* parentRenderObject = renderObject->isText() ? renderObject->parent() : renderObject; ASSERT(parentRenderObject); if (Element* parentRenderObjectElement = toElement(parentRenderObject->node())) { - if (parentRenderObjectElement->hasTagName(SVGNames::altGlyphTag)) + if (isSVGAltGlyphElement(*parentRenderObjectElement)) glyphData.fontData = primaryFont; } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextRunRenderingContext.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextRunRenderingContext.h index e71eca2ca29..382c51feb50 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextRunRenderingContext.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextRunRenderingContext.h @@ -29,7 +29,7 @@ namespace WebCore { class RenderObject; class RenderSVGResource; -class SVGTextRunRenderingContext : public TextRun::RenderingContext { +class SVGTextRunRenderingContext FINAL : public TextRun::RenderingContext { public: static PassRefPtr<SVGTextRunRenderingContext> create(RenderObject* renderer) { @@ -42,9 +42,13 @@ public: RenderSVGResource* activePaintingResource() const { return m_activePaintingResource; } void setActivePaintingResource(RenderSVGResource* object) { m_activePaintingResource = object; } - virtual GlyphData glyphDataForCharacter(const Font&, const TextRun&, WidthIterator&, UChar32 character, bool mirror, int currentCharacter, unsigned& advanceLength); - virtual void drawSVGGlyphs(GraphicsContext*, const TextRun&, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const; - virtual float floatWidthUsingSVGFont(const Font&, const TextRun&, int& charsConsumed, String& glyphName) const; + virtual GlyphData glyphDataForCharacter(const Font&, const TextRun&, WidthIterator&, UChar32 character, bool mirror, int currentCharacter, unsigned& advanceLength) OVERRIDE; + virtual void drawSVGGlyphs(GraphicsContext*, const TextRun&, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const OVERRIDE; + virtual float floatWidthUsingSVGFont(const Font&, const TextRun&, int& charsConsumed, Glyph& glyphId) const OVERRIDE; +#else + virtual GlyphData glyphDataForCharacter(const Font&, const TextRun&, WidthIterator&, UChar32 character, bool mirror, int currentCharacter, unsigned& advanceLength) OVERRIDE { return 0; } + virtual void drawSVGGlyphs(GraphicsContext*, const TextRun&, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const OVERRIDE { } + virtual float floatWidthUsingSVGFont(const Font&, const TextRun&, int& charsConsumed, Glyph& glyphId) const OVERRIDE { return 0; } #endif private: |