1/* 2 * Copyright (C) 2006 Apple Computer, Inc. 3 * Copyright (C) 2009 Google, Inc. 4 * Copyright (C) Research In Motion Limited 2010. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 */ 21 22#include "config.h" 23 24#include "core/rendering/svg/RenderSVGForeignObject.h" 25 26#include "core/rendering/HitTestResult.h" 27#include "core/rendering/LayoutRepainter.h" 28#include "core/rendering/RenderView.h" 29#include "core/rendering/svg/SVGRenderSupport.h" 30#include "core/rendering/svg/SVGRenderingContext.h" 31#include "core/rendering/svg/SVGResourcesCache.h" 32#include "core/svg/SVGForeignObjectElement.h" 33#include "platform/graphics/GraphicsContextStateSaver.h" 34 35namespace WebCore { 36 37RenderSVGForeignObject::RenderSVGForeignObject(SVGForeignObjectElement* node) 38 : RenderSVGBlock(node) 39 , m_needsTransformUpdate(true) 40{ 41} 42 43RenderSVGForeignObject::~RenderSVGForeignObject() 44{ 45} 46 47bool RenderSVGForeignObject::isChildAllowed(RenderObject* child, RenderStyle* style) const 48{ 49 // Disallow arbitary SVG content. Only allow proper <svg xmlns="svgNS"> subdocuments. 50 return !child->isSVG() || child->isSVGRoot(); 51} 52 53void RenderSVGForeignObject::paint(PaintInfo& paintInfo, const LayoutPoint&) 54{ 55 if (paintInfo.context->paintingDisabled() 56 || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)) 57 return; 58 59 PaintInfo childPaintInfo(paintInfo); 60 GraphicsContextStateSaver stateSaver(*childPaintInfo.context); 61 childPaintInfo.applyTransform(localTransform()); 62 63 if (SVGRenderSupport::isOverflowHidden(this)) 64 childPaintInfo.context->clip(m_viewport); 65 66 SVGRenderingContext renderingContext; 67 bool continueRendering = true; 68 if (paintInfo.phase == PaintPhaseForeground) { 69 renderingContext.prepareToRenderSVGContent(this, childPaintInfo); 70 continueRendering = renderingContext.isRenderingPrepared(); 71 } 72 73 if (continueRendering) { 74 // Paint all phases of FO elements atomically, as though the FO element established its 75 // own stacking context. 76 bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip; 77 LayoutPoint childPoint = IntPoint(); 78 childPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; 79 RenderBlock::paint(childPaintInfo, IntPoint()); 80 if (!preservePhase) { 81 childPaintInfo.phase = PaintPhaseChildBlockBackgrounds; 82 RenderBlock::paint(childPaintInfo, childPoint); 83 childPaintInfo.phase = PaintPhaseFloat; 84 RenderBlock::paint(childPaintInfo, childPoint); 85 childPaintInfo.phase = PaintPhaseForeground; 86 RenderBlock::paint(childPaintInfo, childPoint); 87 childPaintInfo.phase = PaintPhaseOutline; 88 RenderBlock::paint(childPaintInfo, childPoint); 89 } 90 } 91} 92 93const AffineTransform& RenderSVGForeignObject::localToParentTransform() const 94{ 95 m_localToParentTransform = localTransform(); 96 m_localToParentTransform.translate(m_viewport.x(), m_viewport.y()); 97 return m_localToParentTransform; 98} 99 100void RenderSVGForeignObject::updateLogicalWidth() 101{ 102 // FIXME: Investigate in size rounding issues 103 // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656 104 setWidth(static_cast<int>(roundf(m_viewport.width()))); 105} 106 107void RenderSVGForeignObject::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const 108{ 109 // FIXME: Investigate in size rounding issues 110 // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656 111 // FIXME: Is this correct for vertical writing mode? 112 computedValues.m_extent = static_cast<int>(roundf(m_viewport.height())); 113 computedValues.m_position = logicalTop; 114} 115 116void RenderSVGForeignObject::layout() 117{ 118 ASSERT(needsLayout()); 119 ASSERT(!view()->layoutStateCachedOffsetsEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree. 120 121 LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(this)); 122 SVGForeignObjectElement* foreign = toSVGForeignObjectElement(node()); 123 124 bool updateCachedBoundariesInParents = false; 125 if (m_needsTransformUpdate) { 126 m_localTransform = foreign->animatedLocalTransform(); 127 m_needsTransformUpdate = false; 128 updateCachedBoundariesInParents = true; 129 } 130 131 FloatRect oldViewport = m_viewport; 132 133 // Cache viewport boundaries 134 SVGLengthContext lengthContext(foreign); 135 FloatPoint viewportLocation(foreign->x()->currentValue()->value(lengthContext), foreign->y()->currentValue()->value(lengthContext)); 136 m_viewport = FloatRect(viewportLocation, FloatSize(foreign->width()->currentValue()->value(lengthContext), foreign->height()->currentValue()->value(lengthContext))); 137 if (!updateCachedBoundariesInParents) 138 updateCachedBoundariesInParents = oldViewport != m_viewport; 139 140 // Set box origin to the foreignObject x/y translation, so positioned objects in XHTML content get correct 141 // positions. A regular RenderBoxModelObject would pull this information from RenderStyle - in SVG those 142 // properties are ignored for non <svg> elements, so we mimic what happens when specifying them through CSS. 143 144 // FIXME: Investigate in location rounding issues - only affects RenderSVGForeignObject & RenderSVGText 145 setLocation(roundedIntPoint(viewportLocation)); 146 147 bool layoutChanged = everHadLayout() && selfNeedsLayout(); 148 RenderBlock::layout(); 149 ASSERT(!needsLayout()); 150 151 // If our bounds changed, notify the parents. 152 if (updateCachedBoundariesInParents) 153 RenderSVGBlock::setNeedsBoundariesUpdate(); 154 155 // Invalidate all resources of this client if our layout changed. 156 if (layoutChanged) 157 SVGResourcesCache::clientLayoutChanged(this); 158 159 repainter.repaintAfterLayout(); 160} 161 162void RenderSVGForeignObject::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, 163 LayoutRect& rect, bool fixed) const 164{ 165 FloatRect r(rect); 166 SVGRenderSupport::computeFloatRectForRepaint(this, paintInvalidationContainer, r, fixed); 167 rect = enclosingLayoutRect(r); 168} 169 170bool RenderSVGForeignObject::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) 171{ 172 // Embedded content is drawn in the foreground phase. 173 if (hitTestAction != HitTestForeground) 174 return false; 175 176 FloatPoint localPoint = localTransform().inverse().mapPoint(pointInParent); 177 178 // Early exit if local point is not contained in clipped viewport area 179 if (SVGRenderSupport::isOverflowHidden(this) && !m_viewport.contains(localPoint)) 180 return false; 181 182 // FOs establish a stacking context, so we need to hit-test all layers. 183 HitTestLocation hitTestLocation(roundedLayoutPoint(localPoint)); 184 return RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), HitTestForeground) 185 || RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), HitTestFloat) 186 || RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), HitTestChildBlockBackgrounds); 187} 188 189} 190