Home | History | Annotate | Download | only in svg
      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 
     35 namespace WebCore {
     36 
     37 RenderSVGForeignObject::RenderSVGForeignObject(SVGForeignObjectElement* node)
     38     : RenderSVGBlock(node)
     39     , m_needsTransformUpdate(true)
     40 {
     41 }
     42 
     43 RenderSVGForeignObject::~RenderSVGForeignObject()
     44 {
     45 }
     46 
     47 bool 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 
     53 void 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 
     93 const 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 
    100 void 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 
    107 void 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 
    116 void 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 
    162 void 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 
    170 bool 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