SVGRenderSupport.cpp [plain text]
#include "config.h"
#if ENABLE(SVG)
#include "SVGRenderSupport.h"
#include "ImageBuffer.h"
#include "RenderObject.h"
#include "RenderSVGContainer.h"
#include "RenderView.h"
#include "SVGResourceClipper.h"
#include "SVGResourceFilter.h"
#include "SVGResourceMasker.h"
#include "SVGStyledElement.h"
#include "SVGURIReference.h"
#include "TransformState.h"
#include "TransformationMatrix.h"
#include <wtf/UnusedParam.h>
namespace WebCore {
SVGRenderBase::~SVGRenderBase()
{
}
IntRect SVGRenderBase::clippedOverflowRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer)
{
if (object->style()->visibility() != VISIBLE && !object->enclosingLayer()->hasVisibleContent())
return IntRect();
IntRect repaintRect = enclosingIntRect(object->repaintRectInLocalCoordinates());
object->computeRectForRepaint(repaintContainer, repaintRect);
return repaintRect;
}
void SVGRenderBase::computeRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
{
repaintRect = object->localToParentTransform().mapRect(repaintRect);
object->parent()->computeRectForRepaint(repaintContainer, repaintRect, fixed);
}
void SVGRenderBase::mapLocalToContainer(const RenderObject* object, RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState)
{
ASSERT(!fixed); ASSERT(useTransforms); transformState.applyTransform(object->localToParentTransform());
object->parent()->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
}
bool SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& repaintRect, SVGResourceFilter*& filter, SVGResourceFilter* rootFilter)
{
#if !ENABLE(FILTERS)
UNUSED_PARAM(filter);
UNUSED_PARAM(rootFilter);
#endif
ASSERT(object);
SVGElement* svgElement = static_cast<SVGElement*>(object->node());
ASSERT(svgElement && svgElement->document() && svgElement->isStyled());
SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement);
const RenderStyle* style = object->style();
ASSERT(style);
const SVGRenderStyle* svgStyle = style->svgStyle();
ASSERT(svgStyle);
float opacity = style->opacity();
if (opacity < 1.0f) {
paintInfo.context->clip(repaintRect);
paintInfo.context->beginTransparencyLayer(opacity);
}
if (ShadowData* shadow = svgStyle->shadow()) {
paintInfo.context->clip(repaintRect);
paintInfo.context->setShadow(IntSize(shadow->x, shadow->y), shadow->blur, shadow->color, style->colorSpace());
paintInfo.context->beginTransparencyLayer(1.0f);
}
#if ENABLE(FILTERS)
AtomicString filterId(svgStyle->filter());
#endif
AtomicString clipperId(svgStyle->clipPath());
AtomicString maskerId(svgStyle->maskElement());
Document* document = object->document();
#if ENABLE(FILTERS)
SVGResourceFilter* newFilter = getFilterById(document, filterId, object);
if (newFilter == rootFilter) {
filter = 0;
filterId = String();
} else
filter = newFilter;
#endif
SVGResourceClipper* clipper = getClipperById(document, clipperId, object);
SVGResourceMasker* masker = getMaskerById(document, maskerId, object);
if (masker) {
masker->addClient(styledElement);
if (!masker->applyMask(paintInfo.context, object))
return false;
} else if (!maskerId.isEmpty())
svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement);
if (clipper) {
clipper->addClient(styledElement);
clipper->applyClip(paintInfo.context, object->objectBoundingBox());
} else if (!clipperId.isEmpty())
svgElement->document()->accessSVGExtensions()->addPendingResource(clipperId, styledElement);
#if ENABLE(FILTERS)
if (filter) {
filter->addClient(styledElement);
if (!filter->prepareFilter(paintInfo.context, object))
return false;
} else if (!filterId.isEmpty())
svgElement->document()->accessSVGExtensions()->addPendingResource(filterId, styledElement);
#endif
return true;
}
void SVGRenderBase::finishRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, SVGResourceFilter*& filter, GraphicsContext* savedContext)
{
#if !ENABLE(FILTERS)
UNUSED_PARAM(filter);
UNUSED_PARAM(savedContext);
#endif
ASSERT(object);
const RenderStyle* style = object->style();
ASSERT(style);
#if ENABLE(FILTERS)
if (filter) {
filter->applyFilter(paintInfo.context, object);
paintInfo.context = savedContext;
}
#endif
float opacity = style->opacity();
if (opacity < 1.0f)
paintInfo.context->endTransparencyLayer();
if (style->svgStyle()->shadow())
paintInfo.context->endTransparencyLayer();
}
void renderSubtreeToImage(ImageBuffer* image, RenderObject* item)
{
ASSERT(item);
ASSERT(image);
ASSERT(image->context());
RenderObject::PaintInfo info(image->context(), IntRect(), PaintPhaseForeground, 0, 0, 0);
RenderSVGContainer* svgContainer = 0;
if (item && item->isSVGContainer())
svgContainer = toRenderSVGContainer(item);
bool drawsContents = svgContainer ? svgContainer->drawsContents() : false;
if (svgContainer && !drawsContents)
svgContainer->setDrawsContents(true);
item->layoutIfNeeded();
item->paint(info, 0, 0);
if (svgContainer && !drawsContents)
svgContainer->setDrawsContents(false);
}
void clampImageBufferSizeToViewport(FrameView* frameView, IntSize& size)
{
if (!frameView)
return;
int viewWidth = frameView->visibleWidth();
int viewHeight = frameView->visibleHeight();
if (size.width() > viewWidth)
size.setWidth(viewWidth);
if (size.height() > viewHeight)
size.setHeight(viewHeight);
}
FloatRect SVGRenderBase::computeContainerBoundingBox(const RenderObject* container, bool includeAllPaintedContent)
{
FloatRect boundingBox;
RenderObject* current = container->firstChild();
for (; current != 0; current = current->nextSibling()) {
FloatRect childBBox = includeAllPaintedContent ? current->repaintRectInLocalCoordinates() : current->objectBoundingBox();
FloatRect childBBoxInLocalCoords = current->localToParentTransform().mapRect(childBBox);
boundingBox.unite(childBBoxInLocalCoords);
}
return boundingBox;
}
void SVGRenderBase::layoutChildren(RenderObject* start, bool selfNeedsLayout)
{
for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
bool needsLayout = selfNeedsLayout;
if (!needsLayout) {
if (SVGElement* element = child->node()->isSVGElement() ? static_cast<SVGElement*>(child->node()) : 0) {
if (element->isStyled())
needsLayout = static_cast<SVGStyledElement*>(element)->hasRelativeValues();
}
}
if (needsLayout)
child->setNeedsLayout(true, false);
child->layoutIfNeeded();
ASSERT(!child->needsLayout());
}
}
bool SVGRenderBase::isOverflowHidden(const RenderObject* object)
{
if (object->style()->overflowX() == OHIDDEN) {
ASSERT(object->style()->overflowY() == OHIDDEN);
return true;
}
return false;
}
FloatRect SVGRenderBase::filterBoundingBoxForRenderer(const RenderObject* object) const
{
#if ENABLE(FILTERS)
SVGResourceFilter* filter = getFilterById(object->document(), object->style()->svgStyle()->filter(), object);
if (filter)
return filter->filterBoundingBox(object->objectBoundingBox());
#else
UNUSED_PARAM(object);
#endif
return FloatRect();
}
FloatRect SVGRenderBase::clipperBoundingBoxForRenderer(const RenderObject* object) const
{
SVGResourceClipper* clipper = getClipperById(object->document(), object->style()->svgStyle()->clipPath(), object);
if (clipper)
return clipper->clipperBoundingBox(object->objectBoundingBox());
return FloatRect();
}
FloatRect SVGRenderBase::maskerBoundingBoxForRenderer(const RenderObject* object) const
{
SVGResourceMasker* masker = getMaskerById(object->document(), object->style()->svgStyle()->maskElement(), object);
if (masker)
return masker->maskerBoundingBox(object->objectBoundingBox());
return FloatRect();
}
void applyTransformToPaintInfo(RenderObject::PaintInfo& paintInfo, const TransformationMatrix& localToAncestorTransform)
{
if (localToAncestorTransform.isIdentity())
return;
paintInfo.context->concatCTM(localToAncestorTransform);
paintInfo.rect = localToAncestorTransform.inverse().mapRect(paintInfo.rect);
}
}
#endif // ENABLE(SVG)