File indexing completed on 2024-04-28 15:24:18

0001 /*
0002  * This file is part of the WebKit project.
0003  *
0004  * Copyright (C) 2006 Apple Computer, Inc.
0005  *               2006 Alexander Kellett <lypanov@kde.org>
0006  *               2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
0007  *               2007 Nikolas Zimmermann <zimmermann@kde.org>
0008  *
0009  * This library is free software; you can redistribute it and/or
0010  * modify it under the terms of the GNU Library General Public
0011  * License as published by the Free Software Foundation; either
0012  * version 2 of the License, or (at your option) any later version.
0013  *
0014  * This library is distributed in the hope that it will be useful,
0015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017  * Library General Public License for more details.
0018  *
0019  * You should have received a copy of the GNU Library General Public License
0020  * along with this library; see the file COPYING.LIB.  If not, write to
0021  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0022  * Boston, MA 02110-1301, USA.
0023  *
0024  */
0025 
0026 #include "wtf/Platform.h"
0027 
0028 #if ENABLE(SVG)
0029 #include "RenderSVGText.h"
0030 
0031 #include "FloatConversion.h"
0032 /*#include "GraphicsContext.h"
0033 #include "PointerEventsHitRules.h"*/
0034 #include "RenderSVGRoot.h"
0035 /*#include "SimpleFontData.h"*/
0036 #include "SVGLengthList.h"
0037 #include "SVGResourceFilter.h"
0038 #include "SVGRootInlineBox.h"
0039 #include "SVGTextElement.h"
0040 #include "SVGTransformList.h"
0041 #include "SVGURIReference.h"
0042 
0043 namespace WebCore
0044 {
0045 
0046 RenderSVGText::RenderSVGText(SVGTextElement *node)
0047     : RenderSVGBlock(node)
0048 {
0049 }
0050 
0051 IntRect RenderSVGText::absoluteClippedOverflowRect()
0052 {
0053     FloatRect repaintRect = absoluteTransform().mapRect(relativeBBox(true));
0054 
0055 #if ENABLE(SVG_FILTERS)
0056     // Filters can expand the bounding box
0057     SVGResourceFilter *filter = getFilterById(document(), SVGURIReference::getTarget(style()->svgStyle()->filter()));
0058     if (filter) {
0059         repaintRect.unite(filter->filterBBoxForItemBBox(repaintRect));
0060     }
0061 #endif
0062 
0063     if (!repaintRect.isEmpty()) {
0064         repaintRect.inflate(1);    // inflate 1 pixel for antialiasing
0065     }
0066 
0067     return enclosingIntRect(repaintRect);
0068 }
0069 
0070 bool RenderSVGText::requiresLayer() const
0071 {
0072     return false;
0073 }
0074 
0075 bool RenderSVGText::calculateLocalTransform()
0076 {
0077     AffineTransform oldTransform = m_localTransform;
0078     m_localTransform = static_cast<SVGTextElement *>(element())->animatedLocalTransform();
0079     return (oldTransform != m_localTransform);
0080 }
0081 
0082 void RenderSVGText::layout()
0083 {
0084     ASSERT(needsLayout());
0085 
0086     // FIXME: This is a hack to avoid the RenderBlock::layout() partial repainting code which is not (yet) SVG aware
0087     setNeedsLayout(true);
0088 
0089     IntRect oldBounds;
0090     IntRect oldOutlineBox;
0091     /*bool checkForRepaint = checkForRepaintDuringLayout();
0092     if (checkForRepaint) {
0093         oldBounds = m_absoluteBounds;
0094         oldOutlineBox = absoluteOutlineBox();
0095     }*/
0096 
0097     // Best guess for a relative starting point
0098     SVGTextElement *text = static_cast<SVGTextElement *>(element());
0099     int xOffset = (int)(text->x()->getFirst().value());
0100     int yOffset = (int)(text->y()->getFirst().value());
0101     setPos(xOffset, yOffset);
0102 
0103     calculateLocalTransform();
0104 
0105     RenderBlock::layout();
0106 
0107     m_absoluteBounds = absoluteClippedOverflowRect();
0108 
0109     /*bool repainted = false;
0110     if (checkForRepaint)
0111         repainted = repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);*/
0112 
0113     setNeedsLayout(false);
0114 }
0115 
0116 InlineBox *RenderSVGText::createInlineBox(bool makePlaceHolderBox, bool isRootLineBox/*, bool isOnlyRun*/)
0117 {
0118     Q_UNUSED(makePlaceHolderBox);
0119     Q_UNUSED(isRootLineBox);
0120     // qCDebug(KHTML_LOG) << "createInlineBox" << makePlaceHolderBox << isRootLineBox;
0121     ASSERT(!isInlineFlow());
0122     InlineFlowBox *flowBox = new(renderArena()) SVGRootInlineBox(this);
0123 
0124     if (!m_firstLineBox) {
0125         m_firstLineBox = m_lastLineBox = flowBox;
0126     } else {
0127         m_lastLineBox->setNextLineBox(flowBox);
0128         flowBox->setPreviousLineBox(m_lastLineBox);
0129         m_lastLineBox = flowBox;
0130     }
0131 
0132     return flowBox;
0133 }
0134 
0135 /*bool RenderSVGText::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
0136 {
0137     PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, style()->svgStyle()->pointerEvents());
0138     bool isVisible = (style()->visibility() == VISIBLE);
0139     if (isVisible || !hitRules.requireVisible) {
0140         if ((hitRules.canHitStroke && (style()->svgStyle()->hasStroke() || !hitRules.requireStroke))
0141             || (hitRules.canHitFill && (style()->svgStyle()->hasFill() || !hitRules.requireFill))) {
0142             AffineTransform totalTransform = absoluteTransform();
0143             double localX, localY;
0144             totalTransform.inverse().map(_x, _y, &localX, &localY);
0145             FloatPoint hitPoint(_x, _y);
0146             return RenderBlock::nodeAtPoint(request, result, (int)localX, (int)localY, _tx, _ty, hitTestAction);
0147         }
0148     }
0149 
0150     return false;
0151 }*/
0152 
0153 void RenderSVGText::absoluteRects(Vector<IntRect> &rects, int, int, bool)
0154 {
0155     RenderSVGRoot *root = findSVGRootObject(parent());
0156     if (!root) {
0157         return;
0158     }
0159 
0160     int x, y;
0161     absolutePosition(x, y);
0162 
0163     AffineTransform htmlParentCtm = root->RenderContainer::absoluteTransform();
0164 
0165     // Don't use relativeBBox here, as it's unites the selection rects. Makes it hard
0166     // to spot errors, if there are any using WebInspector. Individually feed them into 'rects'.
0167     for (InlineRunBox *runBox = firstLineBox(); runBox; runBox = runBox->nextLineBox()) {
0168         ASSERT(runBox->isInlineFlowBox());
0169 
0170         InlineFlowBox *flowBox = static_cast<InlineFlowBox *>(runBox);
0171         for (InlineBox *box = flowBox->firstChild(); box; box = box->nextOnLine()) {
0172             FloatRect boxRect(box->xPos(), box->yPos(), box->width(), box->height());
0173             boxRect.move(narrowPrecisionToFloat(x - htmlParentCtm.e()), narrowPrecisionToFloat(y - htmlParentCtm.f()));
0174             rects.append(enclosingIntRect(absoluteTransform().mapRect(boxRect)));
0175         }
0176     }
0177 }
0178 
0179 void RenderSVGText::paint(PaintInfo &paintInfo, int, int)
0180 {
0181     RenderObject::PaintInfo pi(paintInfo);
0182     //FIXME khtml pi.rect = absoluteTransform().inverse().mapRect(pi.rect);
0183     RenderBlock::paint(pi, 0, 0);
0184 }
0185 
0186 FloatRect RenderSVGText::relativeBBox(bool includeStroke) const
0187 {
0188     FloatRect repaintRect;
0189 
0190     for (InlineRunBox *runBox = firstLineBox(); runBox; runBox = runBox->nextLineBox()) {
0191         ASSERT(runBox->isInlineFlowBox());
0192 
0193         InlineFlowBox *flowBox = static_cast<InlineFlowBox *>(runBox);
0194         for (InlineBox *box = flowBox->firstChild(); box; box = box->nextOnLine()) {
0195             repaintRect.unite(FloatRect(box->xPos(), box->yPos(), box->width(), box->height()));
0196         }
0197     }
0198 
0199     // SVG needs to include the strokeWidth(), not the textStrokeWidth().
0200     if (includeStroke && style()->svgStyle()->hasStroke()) {
0201         float strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, style()->svgStyle()->strokeWidth(), 0.0f);
0202 
0203 #if ENABLE(SVG_FONTS)
0204         /*FIXME khtml const Font& font = style()->font();
0205         if (font.primaryFont()->isSVGFont()) {
0206             float scale = font.unitsPerEm() > 0 ? font.size() / font.unitsPerEm() : 0.0f;
0207 
0208             if (scale != 0.0f)
0209                 strokeWidth /= scale;
0210         }*/
0211 #endif
0212 
0213         repaintRect.inflate(strokeWidth);
0214     }
0215 
0216     repaintRect.move(xPos(), yPos());
0217     return repaintRect;
0218 }
0219 
0220 }
0221 
0222 #endif // ENABLE(SVG)
0223