Home | History | Annotate | Download | only in rendering
      1 /*
      2  * This file is part of the WebKit project.
      3  *
      4  * Copyright (C) 2006 Apple Computer, Inc.
      5  *               2006 Alexander Kellett <lypanov (at) kde.org>
      6  *               2006 Oliver Hunt <ojh16 (at) student.canterbury.ac.nz>
      7  *               2007 Nikolas Zimmermann <zimmermann (at) kde.org>
      8  *               2008 Rob Buis <buis (at) kde.org>
      9  *               2009 Dirk Schulze <krit (at) webkit.org>
     10  *
     11  * This library is free software; you can redistribute it and/or
     12  * modify it under the terms of the GNU Library General Public
     13  * License as published by the Free Software Foundation; either
     14  * version 2 of the License, or (at your option) any later version.
     15  *
     16  * This library is distributed in the hope that it will be useful,
     17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     19  * Library General Public License for more details.
     20  *
     21  * You should have received a copy of the GNU Library General Public License
     22  * along with this library; see the file COPYING.LIB.  If not, write to
     23  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     24  * Boston, MA 02110-1301, USA.
     25  *
     26  */
     27 
     28 #include "config.h"
     29 
     30 #if ENABLE(SVG)
     31 #include "RenderSVGText.h"
     32 
     33 #include "FloatConversion.h"
     34 #include "FloatQuad.h"
     35 #include "GraphicsContext.h"
     36 #include "PointerEventsHitRules.h"
     37 #include "RenderLayer.h"
     38 #include "RenderSVGRoot.h"
     39 #include "SVGLengthList.h"
     40 #include "SVGRenderSupport.h"
     41 #include "SVGResourceFilter.h"
     42 #include "SVGRootInlineBox.h"
     43 #include "SVGTextElement.h"
     44 #include "SVGTransformList.h"
     45 #include "SVGURIReference.h"
     46 #include "SimpleFontData.h"
     47 
     48 namespace WebCore {
     49 
     50 RenderSVGText::RenderSVGText(SVGTextElement* node)
     51     : RenderSVGBlock(node)
     52 {
     53 }
     54 
     55 IntRect RenderSVGText::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
     56 {
     57     return SVGRenderBase::clippedOverflowRectForRepaint(this, repaintContainer);
     58 }
     59 
     60 void RenderSVGText::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
     61 {
     62     SVGRenderBase::computeRectForRepaint(this, repaintContainer, repaintRect, fixed);
     63 }
     64 
     65 void RenderSVGText::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const
     66 {
     67     SVGRenderBase::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState);
     68 }
     69 
     70 void RenderSVGText::layout()
     71 {
     72     ASSERT(needsLayout());
     73     LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
     74 
     75     // Best guess for a relative starting point
     76     SVGTextElement* text = static_cast<SVGTextElement*>(node());
     77     int xOffset = (int)(text->x()->getFirst().value(text));
     78     int yOffset = (int)(text->y()->getFirst().value(text));
     79     setLocation(xOffset, yOffset);
     80 
     81     m_localTransform = text->animatedLocalTransform();
     82 
     83     RenderBlock::layout();
     84 
     85     repainter.repaintAfterLayout();
     86     setNeedsLayout(false);
     87 }
     88 
     89 RootInlineBox* RenderSVGText::createRootInlineBox()
     90 {
     91     RootInlineBox* box = new (renderArena()) SVGRootInlineBox(this);
     92     box->setHasVirtualHeight();
     93     return box;
     94 }
     95 
     96 bool RenderSVGText::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
     97 {
     98     PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, style()->pointerEvents());
     99     bool isVisible = (style()->visibility() == VISIBLE);
    100     if (isVisible || !hitRules.requireVisible) {
    101         if ((hitRules.canHitStroke && (style()->svgStyle()->hasStroke() || !hitRules.requireStroke))
    102             || (hitRules.canHitFill && (style()->svgStyle()->hasFill() || !hitRules.requireFill))) {
    103             FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent);
    104             return RenderBlock::nodeAtPoint(request, result, (int)localPoint.x(), (int)localPoint.y(), 0, 0, hitTestAction);
    105         }
    106     }
    107 
    108     return false;
    109 }
    110 
    111 bool RenderSVGText::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction)
    112 {
    113     ASSERT_NOT_REACHED();
    114     return false;
    115 }
    116 
    117 void RenderSVGText::absoluteRects(Vector<IntRect>& rects, int, int)
    118 {
    119     RenderSVGRoot* root = findSVGRootObject(parent());
    120     if (!root)
    121         return;
    122 
    123     // Don't use objectBoundingBox here, as it's unites the selection rects. Makes it hard
    124     // to spot errors, if there are any using WebInspector. Individually feed them into 'rects'.
    125     for (InlineRunBox* runBox = firstLineBox(); runBox; runBox = runBox->nextLineBox()) {
    126         ASSERT(runBox->isInlineFlowBox());
    127 
    128         InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(runBox);
    129         for (InlineBox* box = flowBox->firstChild(); box; box = box->nextOnLine()) {
    130             FloatRect boxRect(box->x(), box->y(), box->width(), box->height());
    131             // FIXME: crawling up the parent chain to map each rect is very inefficient
    132             // we should compute the absoluteTransform outside this loop first.
    133             rects.append(enclosingIntRect(localToAbsoluteQuad(boxRect).boundingBox()));
    134         }
    135     }
    136 }
    137 
    138 void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads)
    139 {
    140     RenderSVGRoot* root = findSVGRootObject(parent());
    141     if (!root)
    142         return;
    143 
    144     // Don't use objectBoundingBox here, as it's unites the selection rects. Makes it hard
    145     // to spot errors, if there are any using WebInspector. Individually feed them into 'rects'.
    146     for (InlineRunBox* runBox = firstLineBox(); runBox; runBox = runBox->nextLineBox()) {
    147         ASSERT(runBox->isInlineFlowBox());
    148 
    149         InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(runBox);
    150         for (InlineBox* box = flowBox->firstChild(); box; box = box->nextOnLine()) {
    151             FloatRect boxRect(box->x(), box->y(), box->width(), box->height());
    152             // FIXME: crawling up the parent chain to map each quad is very inefficient
    153             // we should compute the absoluteTransform outside this loop first.
    154             quads.append(localToAbsoluteQuad(boxRect));
    155         }
    156     }
    157 }
    158 
    159 void RenderSVGText::paint(PaintInfo& paintInfo, int, int)
    160 {
    161     PaintInfo pi(paintInfo);
    162     pi.context->save();
    163     applyTransformToPaintInfo(pi, localToParentTransform());
    164     RenderBlock::paint(pi, 0, 0);
    165     pi.context->restore();
    166 }
    167 
    168 FloatRect RenderSVGText::objectBoundingBox() const
    169 {
    170     FloatRect boundingBox;
    171 
    172     for (InlineRunBox* runBox = firstLineBox(); runBox; runBox = runBox->nextLineBox()) {
    173         ASSERT(runBox->isInlineFlowBox());
    174 
    175         InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(runBox);
    176         for (InlineBox* box = flowBox->firstChild(); box; box = box->nextOnLine())
    177             boundingBox.unite(FloatRect(box->x(), box->y(), box->width(), box->height()));
    178     }
    179 
    180     boundingBox.move(x(), y());
    181     return boundingBox;
    182 }
    183 
    184 FloatRect RenderSVGText::strokeBoundingBox() const
    185 {
    186     FloatRect repaintRect = objectBoundingBox();
    187 
    188     // SVG needs to include the strokeWidth(), not the textStrokeWidth().
    189     if (style()->svgStyle()->hasStroke()) {
    190         float strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, style()->svgStyle()->strokeWidth(), 1.0f);
    191 
    192 #if ENABLE(SVG_FONTS)
    193         const Font& font = style()->font();
    194         if (font.primaryFont()->isSVGFont()) {
    195             float scale = font.unitsPerEm() > 0 ? font.size() / font.unitsPerEm() : 0.0f;
    196 
    197             if (scale != 0.0f)
    198                 strokeWidth /= scale;
    199         }
    200 #endif
    201 
    202         repaintRect.inflate(strokeWidth);
    203     }
    204 
    205     return repaintRect;
    206 }
    207 
    208 FloatRect RenderSVGText::repaintRectInLocalCoordinates() const
    209 {
    210     FloatRect repaintRect = strokeBoundingBox();
    211 
    212     // FIXME: We need to be careful here. We assume that there is no filter,
    213     // clipper or masker if the rects are empty.
    214     FloatRect rect = filterBoundingBoxForRenderer(this);
    215     if (!rect.isEmpty())
    216         repaintRect = rect;
    217 
    218     rect = clipperBoundingBoxForRenderer(this);
    219     if (!rect.isEmpty())
    220         repaintRect.intersect(rect);
    221 
    222     rect = maskerBoundingBoxForRenderer(this);
    223     if (!rect.isEmpty())
    224         repaintRect.intersect(rect);
    225 
    226     style()->svgStyle()->inflateForShadow(repaintRect);
    227 
    228     return repaintRect;
    229 }
    230 
    231 }
    232 
    233 #endif // ENABLE(SVG)
    234 
    235 // vim:ts=4:noet
    236