Changeset 150349 in webkit
- Timestamp:
- May 18, 2013 8:01:05 PM (11 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r150348 r150349 1 2013-05-18 Simon Fraser <simon.fraser@apple.com> 2 3 Hoist several chunks of code at the top of RenderLayer::paintLayerContents() onto new functions 4 https://bugs.webkit.org/show_bug.cgi?id=116406 5 6 Reviewed by Andreas Kling. 7 8 RenderLayer::paintLayerContents() was getting polluted with code related to filters, 9 clipping and font subpixel quantization, and hard to follow. 10 11 Move three hunks of code into new functions: 12 setupFontSubpixelQuantization() now contains the code related to whether we disable 13 font subpixel quantization on the context. 14 setupClipPath() now contains code related to clipping to shapes and references. 15 setupFilters() and applyFilters() contain code related to CSS filters. 16 17 As part of this, the interaction with FilterEffectRendererHelper was simplified. 18 It was convenient for setupFilters() to return a FilterEffectRendererHelper object 19 if successful, so we use an OwnPtr<FilterEffectRendererHelper> now. In addition, 20 the GraphicsContext swapping was moved from FilterEffectRendererHelper code into RenderLayer 21 to make it easier to follow. FilterEffectRendererHelper no longer holds on to 22 the old GraphicsContext. 23 24 No behavior change. 25 26 * rendering/FilterEffectRenderer.cpp: 27 (WebCore::FilterEffectRendererHelper::filterContext): 28 (WebCore::FilterEffectRendererHelper::beginFilterEffect): 29 (WebCore::FilterEffectRendererHelper::applyFilterEffect): 30 * rendering/FilterEffectRenderer.h: 31 (WebCore::FilterEffectRendererHelper::FilterEffectRendererHelper): 32 (WebCore::FilterEffectRendererHelper::hasStartedFilterEffect): 33 (FilterEffectRendererHelper): 34 * rendering/RenderLayer.cpp: 35 (WebCore::RenderLayer::setupFontSubpixelQuantization): 36 (WebCore::RenderLayer::setupClipPath): 37 (WebCore::RenderLayer::setupFilters): 38 (WebCore::RenderLayer::applyFilters): 39 (WebCore::RenderLayer::paintLayerContents): 40 * rendering/RenderLayer.h: 41 1 42 2013-05-18 Simon Fraser <simon.fraser@apple.com> 2 43 -
trunk/Source/WebCore/rendering/FilterEffectRenderer.cpp
r148518 r150349 471 471 return true; 472 472 } 473 474 GraphicsContext* FilterEffectRendererHelper::beginFilterEffect(GraphicsContext* oldContext) 473 474 GraphicsContext* FilterEffectRendererHelper::filterContext() const 475 { 476 if (!m_haveFilterEffect) 477 return 0; 478 479 FilterEffectRenderer* filter = m_renderLayer->filterRenderer(); 480 return filter->inputContext(); 481 } 482 483 bool FilterEffectRendererHelper::beginFilterEffect() 475 484 { 476 485 ASSERT(m_renderLayer); … … 483 492 // Disable the filters and continue. 484 493 m_haveFilterEffect = false; 485 return oldContext; 486 } 487 488 m_savedGraphicsContext = oldContext; 494 return false; 495 } 489 496 490 497 // Translate the context so that the contents of the layer is captuterd in the offscreen memory buffer. … … 493 500 sourceGraphicsContext->clearRect(m_repaintRect); 494 501 sourceGraphicsContext->clip(m_repaintRect); 495 496 return sourceGraphicsContext; 497 } 498 499 GraphicsContext* FilterEffectRendererHelper::applyFilterEffect() 502 503 m_startedFilterEffect = true; 504 return true; 505 } 506 507 void FilterEffectRendererHelper::applyFilterEffect(GraphicsContext* destinationContext) 500 508 { 501 509 ASSERT(m_haveFilterEffect && m_renderLayer->filterRenderer()); … … 509 517 destRect.move(m_paintOffset.x(), m_paintOffset.y()); 510 518 511 m_savedGraphicsContext->drawImageBuffer(filter->output(), m_renderLayer->renderer()->style()->colorSpace(), pixelSnappedIntRect(destRect), CompositeSourceOver);519 destinationContext->drawImageBuffer(filter->output(), m_renderLayer->renderer()->style()->colorSpace(), pixelSnappedIntRect(destRect), CompositeSourceOver); 512 520 513 521 filter->clearIntermediateResults(); 514 515 return m_savedGraphicsContext;516 522 } 517 523 -
trunk/Source/WebCore/rendering/FilterEffectRenderer.h
r142823 r150349 57 57 public: 58 58 FilterEffectRendererHelper(bool haveFilterEffect) 59 : m_savedGraphicsContext(0) 60 , m_renderLayer(0) 59 : m_renderLayer(0) 61 60 , m_haveFilterEffect(haveFilterEffect) 61 , m_startedFilterEffect(false) 62 62 { 63 63 } 64 64 65 65 bool haveFilterEffect() const { return m_haveFilterEffect; } 66 bool hasStartedFilterEffect() const { return m_s avedGraphicsContext; }66 bool hasStartedFilterEffect() const { return m_startedFilterEffect; } 67 67 68 68 bool prepareFilterEffect(RenderLayer*, const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect, const LayoutRect& layerRepaintRect); 69 GraphicsContext* beginFilterEffect(GraphicsContext* oldContext); 70 GraphicsContext* applyFilterEffect(); 69 bool beginFilterEffect(); 70 void applyFilterEffect(GraphicsContext* destinationContext); 71 72 GraphicsContext* filterContext() const; 71 73 72 74 const LayoutRect& repaintRect() const { return m_repaintRect; } 73 75 private: 74 GraphicsContext* m_savedGraphicsContext; 75 RenderLayer* m_renderLayer; 76 RenderLayer* m_renderLayer; // FIXME: this is mainly used to get the FilterEffectRenderer. FilterEffectRendererHelper should be weaned off it. 76 77 LayoutPoint m_paintOffset; 77 78 LayoutRect m_repaintRect; 78 79 bool m_haveFilterEffect; 80 bool m_startedFilterEffect; 79 81 }; 80 82 -
trunk/Source/WebCore/rendering/RenderLayer.cpp
r150214 r150349 3689 3689 } 3690 3690 3691 bool RenderLayer::setupFontSubpixelQuantization(GraphicsContext* context, bool& didQuantizeFonts) 3692 { 3693 if (context->paintingDisabled()) 3694 return false; 3695 3696 bool scrollingOnMainThread = true; 3697 Frame* frame = renderer()->frame(); 3698 #if ENABLE(THREADED_SCROLLING) 3699 if (frame) { 3700 if (Page* page = frame->page()) { 3701 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 3702 scrollingOnMainThread = scrollingCoordinator->shouldUpdateScrollLayerPositionOnMainThread(); 3703 } 3704 } 3705 #endif 3706 3707 // FIXME: We shouldn't have to disable subpixel quantization for overflow clips or subframes once we scroll those 3708 // things on the scrolling thread. 3709 bool contentsScrollByPainting = (renderer()->hasOverflowClip() && !usesCompositedScrolling()) || (frame && frame->ownerElement()); 3710 if (scrollingOnMainThread || contentsScrollByPainting) { 3711 didQuantizeFonts = context->shouldSubpixelQuantizeFonts(); 3712 context->setShouldSubpixelQuantizeFonts(false); 3713 return true; 3714 } 3715 return false; 3716 } 3717 3718 bool RenderLayer::setupClipPath(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, const LayoutPoint& offsetFromRoot, IntRect& rootRelativeBounds, bool& rootRelativeBoundsComputed) 3719 { 3720 if (!renderer()->hasClipPath() || context->paintingDisabled()) 3721 return false; 3722 3723 RenderStyle* style = renderer()->style(); 3724 3725 ASSERT(style->clipPath()); 3726 if (style->clipPath()->getOperationType() == ClipPathOperation::SHAPE) { 3727 ShapeClipPathOperation* clipPath = static_cast<ShapeClipPathOperation*>(style->clipPath()); 3728 3729 if (!rootRelativeBoundsComputed) { 3730 rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0); 3731 rootRelativeBoundsComputed = true; 3732 } 3733 3734 context->save(); 3735 context->clipPath(clipPath->path(rootRelativeBounds), clipPath->windRule()); 3736 return true; 3737 } 3738 3739 #if ENABLE(SVG) 3740 if (style->clipPath()->getOperationType() == ClipPathOperation::REFERENCE) { 3741 ReferenceClipPathOperation* referenceClipPathOperation = static_cast<ReferenceClipPathOperation*>(style->clipPath()); 3742 Document* document = renderer()->document(); 3743 Element* element = document ? document->getElementById(referenceClipPathOperation->fragment()) : 0; 3744 if (element && element->hasTagName(SVGNames::clipPathTag) && element->renderer()) { 3745 if (!rootRelativeBoundsComputed) { 3746 rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0); 3747 rootRelativeBoundsComputed = true; 3748 } 3749 3750 // FIXME: This should use a safer cast such as toRenderSVGResourceContainer(). 3751 // FIXME: Should this do a context->save() and return true so we restore the context? 3752 static_cast<RenderSVGResourceClipper*>(element->renderer())->applyClippingToContext(renderer(), rootRelativeBounds, paintingInfo.paintDirtyRect, context); 3753 } 3754 } 3755 #endif 3756 3757 return false; 3758 } 3759 3760 #if ENABLE(CSS_FILTERS) 3761 PassOwnPtr<FilterEffectRendererHelper> RenderLayer::setupFilters(GraphicsContext* context, LayerPaintingInfo& paintingInfo, const LayoutPoint& offsetFromRoot, IntRect& rootRelativeBounds, bool& rootRelativeBoundsComputed) 3762 { 3763 if (context->paintingDisabled()) 3764 return nullptr; 3765 3766 bool hasPaintedFilter = filterRenderer() && paintsWithFilters(); 3767 if (!hasPaintedFilter) 3768 return nullptr; 3769 3770 OwnPtr<FilterEffectRendererHelper> filterPainter = adoptPtr(new FilterEffectRendererHelper(hasPaintedFilter)); 3771 if (!filterPainter->haveFilterEffect()) 3772 return nullptr; 3773 3774 RenderLayerFilterInfo* filterInfo = this->filterInfo(); 3775 ASSERT(filterInfo); 3776 LayoutRect filterRepaintRect = filterInfo->dirtySourceRect(); 3777 filterRepaintRect.move(offsetFromRoot.x(), offsetFromRoot.y()); 3778 3779 if (!rootRelativeBoundsComputed) { 3780 rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0); 3781 rootRelativeBoundsComputed = true; 3782 } 3783 3784 if (filterPainter->prepareFilterEffect(this, rootRelativeBounds, paintingInfo.paintDirtyRect, filterRepaintRect)) { 3785 // Now we know for sure, that the source image will be updated, so we can revert our tracking repaint rect back to zero. 3786 filterInfo->resetDirtySourceRect(); 3787 3788 if (!filterPainter->beginFilterEffect()) 3789 return nullptr; 3790 3791 // Check that we didn't fail to allocate the graphics context for the offscreen buffer. 3792 ASSERT(filterPainter->hasStartedFilterEffect()); 3793 3794 paintingInfo.paintDirtyRect = filterPainter->repaintRect(); 3795 // If the filter needs the full source image, we need to avoid using the clip rectangles. 3796 // Otherwise, if for example this layer has overflow:hidden, a drop shadow will not compute correctly. 3797 // Note that we will still apply the clipping on the final rendering of the filter. 3798 paintingInfo.clipToDirtyRect = !filterRenderer()->hasFilterThatMovesPixels(); 3799 return filterPainter.release(); 3800 } 3801 return nullptr; 3802 } 3803 3804 GraphicsContext* RenderLayer::applyFilters(FilterEffectRendererHelper* filterPainter, GraphicsContext* originalContext, LayerPaintingInfo& paintingInfo, LayerFragments& layerFragments) 3805 { 3806 ASSERT(filterPainter->hasStartedFilterEffect()); 3807 // Apply the correct clipping (ie. overflow: hidden). 3808 // FIXME: It is incorrect to just clip to the damageRect here once multiple fragments are involved. 3809 ClipRect backgroundRect = layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect; 3810 clipToRect(paintingInfo.rootLayer, originalContext, paintingInfo.paintDirtyRect, backgroundRect); 3811 filterPainter->applyFilterEffect(originalContext); 3812 restoreClip(originalContext, paintingInfo.paintDirtyRect, backgroundRect); 3813 return originalContext; 3814 } 3815 #endif 3816 3691 3817 void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) 3692 3818 { … … 3712 3838 bool shouldPaintContent = m_hasVisibleContent && isSelfPaintingLayer && !isPaintingOverlayScrollbars; 3713 3839 3714 GraphicsContext* transparencyLayerContext = context;3715 3716 3840 if (localPaintFlags & PaintLayerPaintingRootBackgroundOnly && !renderer()->isRenderView() && !renderer()->isRoot()) 3717 3841 return; … … 3726 3850 bool rootRelativeBoundsComputed = false; 3727 3851 3728 bool didQuantizeFonts = true;3729 bool scrollingOnMainThread = true;3730 Frame* frame = renderer()->frame();3731 #if ENABLE(THREADED_SCROLLING)3732 if (frame) {3733 if (Page* page = frame->page()) {3734 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())3735 scrollingOnMainThread = scrollingCoordinator->shouldUpdateScrollLayerPositionOnMainThread();3736 }3737 }3738 #endif3739 3740 3852 // FIXME: We shouldn't have to disable subpixel quantization for overflow clips or subframes once we scroll those 3741 3853 // things on the scrolling thread. 3742 bool needToAdjustSubpixelQuantization = scrollingOnMainThread || (renderer()->hasOverflowClip() && !usesCompositedScrolling()) || (frame && frame->ownerElement()); 3743 if (needToAdjustSubpixelQuantization) { 3744 didQuantizeFonts = context->shouldSubpixelQuantizeFonts(); 3745 context->setShouldSubpixelQuantizeFonts(false); 3746 } 3854 bool didQuantizeFonts = true; 3855 bool needToAdjustSubpixelQuantization = setupFontSubpixelQuantization(context, didQuantizeFonts); 3747 3856 3748 3857 // Apply clip-path to context. 3749 bool hasClipPath = false; 3750 RenderStyle* style = renderer()->style(); 3751 if (renderer()->hasClipPath() && !context->paintingDisabled() && style) { 3752 ASSERT(style->clipPath()); 3753 if (style->clipPath()->getOperationType() == ClipPathOperation::SHAPE) { 3754 hasClipPath = true; 3755 context->save(); 3756 ShapeClipPathOperation* clipPath = static_cast<ShapeClipPathOperation*>(style->clipPath()); 3757 3758 if (!rootRelativeBoundsComputed) { 3759 rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0); 3760 rootRelativeBoundsComputed = true; 3761 } 3762 3763 context->clipPath(clipPath->path(rootRelativeBounds), clipPath->windRule()); 3764 } 3765 #if ENABLE(SVG) 3766 else if (style->clipPath()->getOperationType() == ClipPathOperation::REFERENCE) { 3767 ReferenceClipPathOperation* referenceClipPathOperation = static_cast<ReferenceClipPathOperation*>(style->clipPath()); 3768 Document* document = renderer()->document(); 3769 // FIXME: It doesn't work with forward or external SVG references (https://bugs.webkit.org/show_bug.cgi?id=90405) 3770 Element* element = document ? document->getElementById(referenceClipPathOperation->fragment()) : 0; 3771 if (element && element->hasTagName(SVGNames::clipPathTag) && element->renderer()) { 3772 if (!rootRelativeBoundsComputed) { 3773 rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0); 3774 rootRelativeBoundsComputed = true; 3775 } 3776 3777 // FIXME: This should use a safer cast such as toRenderSVGResourceContainer(). 3778 static_cast<RenderSVGResourceClipper*>(element->renderer())->applyClippingToContext(renderer(), rootRelativeBounds, paintingInfo.paintDirtyRect, context); 3779 } 3780 } 3781 #endif 3782 } 3858 bool hasClipPath = setupClipPath(context, paintingInfo, offsetFromRoot, rootRelativeBounds, rootRelativeBoundsComputed); 3783 3859 3784 3860 LayerPaintingInfo localPaintingInfo(paintingInfo); 3861 3862 GraphicsContext* transparencyLayerContext = context; 3785 3863 #if ENABLE(CSS_FILTERS) 3786 FilterEffectRendererHelper filterPainter(filterRenderer() && paintsWithFilters()); 3787 if (filterPainter.haveFilterEffect() && !context->paintingDisabled()) { 3788 RenderLayerFilterInfo* filterInfo = this->filterInfo(); 3789 ASSERT(filterInfo); 3790 LayoutRect filterRepaintRect = filterInfo->dirtySourceRect(); 3791 filterRepaintRect.move(offsetFromRoot.x(), offsetFromRoot.y()); 3792 3793 if (!rootRelativeBoundsComputed) { 3794 rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0); 3795 rootRelativeBoundsComputed = true; 3796 } 3797 3798 if (filterPainter.prepareFilterEffect(this, rootRelativeBounds, paintingInfo.paintDirtyRect, filterRepaintRect)) { 3799 // Now we know for sure, that the source image will be updated, so we can revert our tracking repaint rect back to zero. 3800 filterInfo->resetDirtySourceRect(); 3801 3802 // Rewire the old context to a memory buffer, so that we can capture the contents of the layer. 3803 // NOTE: We saved the old context in the "transparencyLayerContext" local variable, to be able to start a transparency layer 3804 // on the original context and avoid duplicating "beginFilterEffect" after each transparency layer call. Also, note that 3805 // beginTransparencyLayers will only create a single lazy transparency layer, even though it is called twice in this method. 3806 context = filterPainter.beginFilterEffect(context); 3807 3808 // Check that we didn't fail to allocate the graphics context for the offscreen buffer. 3809 if (filterPainter.hasStartedFilterEffect()) { 3810 localPaintingInfo.paintDirtyRect = filterPainter.repaintRect(); 3811 // If the filter needs the full source image, we need to avoid using the clip rectangles. 3812 // Otherwise, if for example this layer has overflow:hidden, a drop shadow will not compute correctly. 3813 // Note that we will still apply the clipping on the final rendering of the filter. 3814 localPaintingInfo.clipToDirtyRect = !filterRenderer()->hasFilterThatMovesPixels(); 3815 } 3816 } 3817 } 3818 3819 if (filterPainter.hasStartedFilterEffect() && haveTransparency) { 3820 // 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. 3821 beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, paintingInfo.paintDirtyRect, localPaintingInfo.paintBehavior); 3864 OwnPtr<FilterEffectRendererHelper> filterPainter = setupFilters(context, localPaintingInfo, offsetFromRoot, rootRelativeBounds, rootRelativeBoundsComputed); 3865 if (filterPainter) { 3866 context = filterPainter->filterContext(); 3867 if (context != transparencyLayerContext && haveTransparency) { 3868 // 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. 3869 beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, paintingInfo.paintDirtyRect, localPaintingInfo.paintBehavior); 3870 } 3822 3871 } 3823 3872 #endif … … 3885 3934 3886 3935 #if ENABLE(CSS_FILTERS) 3887 if (filterPainter.hasStartedFilterEffect()) { 3888 // Apply the correct clipping (ie. overflow: hidden). 3889 // FIXME: It is incorrect to just clip to the damageRect here once multiple fragments are involved. 3890 ClipRect backgroundRect = layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect; 3891 clipToRect(localPaintingInfo.rootLayer, transparencyLayerContext, localPaintingInfo.paintDirtyRect, backgroundRect); 3892 context = filterPainter.applyFilterEffect(); 3893 restoreClip(transparencyLayerContext, localPaintingInfo.paintDirtyRect, backgroundRect); 3936 if (filterPainter) { 3937 context = applyFilters(filterPainter.get(), transparencyLayerContext, localPaintingInfo, layerFragments); 3938 filterPainter.clear(); 3894 3939 } 3895 3940 #endif -
trunk/Source/WebCore/rendering/RenderLayer.h
r149066 r150349 54 54 #if ENABLE(CSS_FILTERS) 55 55 class FilterEffectRenderer; 56 class FilterEffectRendererHelper; 56 57 class FilterOperations; 57 58 class RenderLayerFilterInfo; … … 935 936 bool clipToDirtyRect; 936 937 }; 937 938 939 bool setupFontSubpixelQuantization(GraphicsContext*, bool& didQuantizeFonts); 940 bool setupClipPath(GraphicsContext*, const LayerPaintingInfo&, const LayoutPoint& offsetFromRoot, IntRect& rootRelativeBounds, bool& rootRelativeBoundsComputed); 941 #if ENABLE(CSS_FILTERS) 942 PassOwnPtr<FilterEffectRendererHelper> setupFilters(GraphicsContext*, LayerPaintingInfo&, const LayoutPoint& offsetFromRoot, IntRect& rootRelativeBounds, bool& rootRelativeBoundsComputed); 943 GraphicsContext* applyFilters(FilterEffectRendererHelper*, GraphicsContext* originalContext, LayerPaintingInfo&, LayerFragments&); 944 #endif 945 938 946 void paintLayer(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags); 939 947 void paintLayerContentsAndReflection(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags);
Note: See TracChangeset
for help on using the changeset viewer.