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