Warning, file /frameworks/khtml/src/rendering/SVGCharacterLayoutInfo.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * This file is part of the WebKit project.
0003  *
0004  * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  *
0021  */
0022 
0023 #include "wtf/Platform.h"
0024 
0025 #if ENABLE(SVG)
0026 #include "SVGCharacterLayoutInfo.h"
0027 
0028 //#include "InlineFlowBox.h"
0029 //#include "InlineTextBox.h"
0030 #include "SVGLengthList.h"
0031 #include "SVGNumberList.h"
0032 #include "SVGTextPositioningElement.h"
0033 #include "RenderSVGTextPath.h"
0034 
0035 #include <float.h>
0036 
0037 
0038 namespace WebCore
0039 {
0040 using namespace khtml;
0041 using namespace DOM;
0042 
0043 // Helper function
0044 static float calculateBaselineShift(RenderObject *item)
0045 {
0046     const Font &font = item->style()->htmlFont();
0047     const SVGRenderStyle *svgStyle = item->style()->svgStyle();
0048 
0049     float baselineShift = 0.0f;
0050     if (svgStyle->baselineShift() == BS_LENGTH) {
0051         CSSPrimitiveValueImpl *primitive = static_cast<CSSPrimitiveValueImpl *>(svgStyle->baselineShiftValue());
0052         baselineShift = primitive->floatValue();
0053 
0054         /*FIXME khtml if (primitive->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE)
0055             baselineShift = baselineShift / 100.0f * font.pixelSize();*/
0056     } else {
0057         float baselineAscent = font.ascent() + font.descent();
0058 
0059         switch (svgStyle->baselineShift()) {
0060         case BS_BASELINE:
0061             break;
0062         case BS_SUB:
0063             baselineShift = -baselineAscent / 2.0f;
0064             break;
0065         case BS_SUPER:
0066             baselineShift = baselineAscent / 2.0f;
0067             break;
0068         default:
0069             ASSERT_NOT_REACHED();
0070         }
0071     }
0072 
0073     return baselineShift;
0074 }
0075 
0076 SVGCharacterLayoutInfo::SVGCharacterLayoutInfo(Vector<SVGChar> &chars)
0077     : curx(0.0f)
0078     , cury(0.0f)
0079     , angle(0.0f)
0080     , dx(0.0f)
0081     , dy(0.0f)
0082     , shiftx(0.0f)
0083     , shifty(0.0f)
0084     , pathExtraAdvance(0.0f)
0085     , pathTextLength(0.0f)
0086     , pathChunkLength(0.0f)
0087     , svgChars(chars)
0088     , nextDrawnSeperated(false)
0089     , xStackChanged(false)
0090     , yStackChanged(false)
0091     , dxStackChanged(false)
0092     , dyStackChanged(false)
0093     , angleStackChanged(false)
0094     , baselineShiftStackChanged(false)
0095     , pathLayout(false)
0096     , currentOffset(0.0f)
0097     , startOffset(0.0f)
0098     , layoutPathLength(0.0f)
0099 {
0100 }
0101 
0102 bool SVGCharacterLayoutInfo::xValueAvailable() const
0103 {
0104     return xStack.isEmpty() ? false : xStack.last().position() < xStack.last().size();
0105 }
0106 
0107 bool SVGCharacterLayoutInfo::yValueAvailable() const
0108 {
0109     return yStack.isEmpty() ? false : yStack.last().position() < yStack.last().size();
0110 }
0111 
0112 bool SVGCharacterLayoutInfo::dxValueAvailable() const
0113 {
0114     return dxStack.isEmpty() ? false : dxStack.last().position() < dxStack.last().size();
0115 }
0116 
0117 bool SVGCharacterLayoutInfo::dyValueAvailable() const
0118 {
0119     return dyStack.isEmpty() ? false : dyStack.last().position() < dyStack.last().size();
0120 }
0121 
0122 bool SVGCharacterLayoutInfo::angleValueAvailable() const
0123 {
0124     return angleStack.isEmpty() ? false : angleStack.last().position() < angleStack.last().size();
0125 }
0126 
0127 bool SVGCharacterLayoutInfo::baselineShiftValueAvailable() const
0128 {
0129     return !baselineShiftStack.isEmpty();
0130 }
0131 
0132 float SVGCharacterLayoutInfo::xValueNext() const
0133 {
0134     ASSERT(!xStack.isEmpty());
0135     return xStack.last().valueAtCurrentPosition();
0136 }
0137 
0138 float SVGCharacterLayoutInfo::yValueNext() const
0139 {
0140     ASSERT(!yStack.isEmpty());
0141     return yStack.last().valueAtCurrentPosition();
0142 }
0143 
0144 float SVGCharacterLayoutInfo::dxValueNext() const
0145 {
0146     ASSERT(!dxStack.isEmpty());
0147     return dxStack.last().valueAtCurrentPosition();
0148 }
0149 
0150 float SVGCharacterLayoutInfo::dyValueNext() const
0151 {
0152     ASSERT(!dyStack.isEmpty());
0153     return dyStack.last().valueAtCurrentPosition();
0154 }
0155 
0156 float SVGCharacterLayoutInfo::angleValueNext() const
0157 {
0158     ASSERT(!angleStack.isEmpty());
0159     return angleStack.last().valueAtCurrentPosition();
0160 }
0161 
0162 float SVGCharacterLayoutInfo::baselineShiftValueNext() const
0163 {
0164     ASSERT(!baselineShiftStack.isEmpty());
0165     return baselineShiftStack.last();
0166 }
0167 
0168 void SVGCharacterLayoutInfo::processedSingleCharacter()
0169 {
0170     xStackWalk();
0171     yStackWalk();
0172     dxStackWalk();
0173     dyStackWalk();
0174     angleStackWalk();
0175     baselineShiftStackWalk();
0176 }
0177 
0178 void SVGCharacterLayoutInfo::processedChunk(float savedShiftX, float savedShiftY)
0179 {
0180     // baseline-shift doesn't span across ancestors, unlike dx/dy.
0181     curx += savedShiftX - shiftx;
0182     cury += savedShiftY - shifty;
0183 
0184     if (inPathLayout()) {
0185         shiftx = savedShiftX;
0186         shifty = savedShiftY;
0187     }
0188 
0189     // rotation also doesn't span
0190     angle = 0.0f;
0191 
0192     if (xStackChanged) {
0193         ASSERT(!xStack.isEmpty());
0194         xStack.removeLast();
0195         xStackChanged = false;
0196     }
0197 
0198     if (yStackChanged) {
0199         ASSERT(!yStack.isEmpty());
0200         yStack.removeLast();
0201         yStackChanged = false;
0202     }
0203 
0204     if (dxStackChanged) {
0205         ASSERT(!dxStack.isEmpty());
0206         dxStack.removeLast();
0207         dxStackChanged = false;
0208     }
0209 
0210     if (dyStackChanged) {
0211         ASSERT(!dyStack.isEmpty());
0212         dyStack.removeLast();
0213         dyStackChanged = false;
0214     }
0215 
0216     if (angleStackChanged) {
0217         ASSERT(!angleStack.isEmpty());
0218         angleStack.removeLast();
0219         angleStackChanged = false;
0220     }
0221 
0222     if (baselineShiftStackChanged) {
0223         ASSERT(!baselineShiftStack.isEmpty());
0224         baselineShiftStack.removeLast();
0225         baselineShiftStackChanged = false;
0226     }
0227 }
0228 
0229 bool SVGCharacterLayoutInfo::nextPathLayoutPointAndAngle(float glyphAdvance, float extraAdvance, float newOffset)
0230 {
0231     if (layoutPathLength <= 0.0f) {
0232         return false;
0233     }
0234 
0235     if (newOffset != FLT_MIN) {
0236         currentOffset = startOffset + newOffset;
0237     }
0238 
0239     // Respect translation along path (extraAdvance is orthogonal to the path)
0240     currentOffset += extraAdvance;
0241 
0242     float offset = currentOffset + glyphAdvance / 2.0f;
0243     currentOffset += glyphAdvance + pathExtraAdvance;
0244 
0245     if (offset < 0.0f || offset > layoutPathLength) {
0246         return false;
0247     }
0248 
0249     bool ok = false;
0250     FloatPoint point = layoutPath.pointAtLength(offset, ok);
0251     ASSERT(ok);
0252 
0253     curx = point.x();
0254     cury = point.y();
0255 
0256     angle = layoutPath.normalAngleAtLength(offset, ok);
0257     ASSERT(ok);
0258 
0259     // fprintf(stderr, "t: %f, x: %f, y: %f, angle: %f, glyphAdvance: %f\n", currentOffset, x, y, angle, glyphAdvance);
0260     return true;
0261 }
0262 
0263 bool SVGCharacterLayoutInfo::inPathLayout() const
0264 {
0265     return pathLayout;
0266 }
0267 
0268 void SVGCharacterLayoutInfo::setInPathLayout(bool value)
0269 {
0270     pathLayout = value;
0271 
0272     pathExtraAdvance = 0.0f;
0273     pathTextLength = 0.0f;
0274     pathChunkLength = 0.0f;
0275 }
0276 
0277 void SVGCharacterLayoutInfo::addLayoutInformation(InlineFlowBox *flowBox, float textAnchorStartOffset)
0278 {
0279     bool isInitialLayout = xStack.isEmpty() && yStack.isEmpty() &&
0280                            dxStack.isEmpty() && dyStack.isEmpty() &&
0281                            angleStack.isEmpty() && baselineShiftStack.isEmpty() &&
0282                            curx == 0.0f && cury == 0.0f;
0283 
0284     RenderSVGTextPath *textPath = static_cast<RenderSVGTextPath *>(flowBox->object());
0285     Path path = textPath->layoutPath();
0286 
0287     float baselineShift = calculateBaselineShift(textPath);
0288 
0289     layoutPath = path;
0290     layoutPathLength = path.length();
0291 
0292     if (layoutPathLength <= 0.0f) {
0293         return;
0294     }
0295 
0296     startOffset = textPath->startOffset();
0297 
0298     if (textPath->startOffset() >= 0.0f && textPath->startOffset() <= 1.0f) {
0299         startOffset *= layoutPathLength;
0300     }
0301 
0302     startOffset += textAnchorStartOffset;
0303     currentOffset = startOffset;
0304 
0305     // Only baseline-shift is handled through the normal layout system
0306     addStackContent(BaselineShiftStack, baselineShift);
0307 
0308     if (isInitialLayout) {
0309         xStackChanged = false;
0310         yStackChanged = false;
0311         dxStackChanged = false;
0312         dyStackChanged = false;
0313         angleStackChanged = false;
0314         baselineShiftStackChanged = false;
0315     }
0316 }
0317 
0318 void SVGCharacterLayoutInfo::addLayoutInformation(SVGTextPositioningElement *element)
0319 {
0320     bool isInitialLayout = xStack.isEmpty() && yStack.isEmpty() &&
0321                            dxStack.isEmpty() && dyStack.isEmpty() &&
0322                            angleStack.isEmpty() && baselineShiftStack.isEmpty() &&
0323                            curx == 0.0f && cury == 0.0f;
0324 
0325     float baselineShift = calculateBaselineShift(element->renderer());
0326 
0327     addStackContent(XStack, element->x());
0328     addStackContent(YStack, element->y());
0329     addStackContent(DxStack, element->dx());
0330     addStackContent(DyStack, element->dy());
0331     addStackContent(AngleStack, element->rotate());
0332     addStackContent(BaselineShiftStack, baselineShift);
0333 
0334     if (isInitialLayout) {
0335         xStackChanged = false;
0336         yStackChanged = false;
0337         dxStackChanged = false;
0338         dyStackChanged = false;
0339         angleStackChanged = false;
0340         baselineShiftStackChanged = false;
0341     }
0342 }
0343 
0344 void SVGCharacterLayoutInfo::addStackContent(StackType type, SVGNumberList *list)
0345 {
0346     unsigned length = list->numberOfItems();
0347     if (!length) {
0348         return;
0349     }
0350 
0351     PositionedFloatVector newLayoutInfo;
0352 
0353     // TODO: Convert more efficiently!
0354     ExceptionCode ec = 0;
0355     for (unsigned i = 0; i < length; ++i) {
0356         float value = list->getItem(i, ec);
0357         ASSERT(ec == 0);
0358 
0359         newLayoutInfo.append(value);
0360     }
0361 
0362     addStackContent(type, newLayoutInfo);
0363 }
0364 
0365 void SVGCharacterLayoutInfo::addStackContent(StackType type, SVGLengthList *list)
0366 {
0367     unsigned length = list->numberOfItems();
0368     if (!length) {
0369         return;
0370     }
0371 
0372     PositionedFloatVector newLayoutInfo;
0373 
0374     ExceptionCode ec = 0;
0375     for (unsigned i = 0; i < length; ++i) {
0376         float value = list->getItem(i, ec).value();
0377         ASSERT(ec == 0);
0378 
0379         newLayoutInfo.append(value);
0380     }
0381 
0382     addStackContent(type, newLayoutInfo);
0383 }
0384 
0385 void SVGCharacterLayoutInfo::addStackContent(StackType type, const PositionedFloatVector &list)
0386 {
0387     switch (type) {
0388     case XStack:
0389         xStackChanged = true;
0390         xStack.append(list);
0391         break;
0392     case YStack:
0393         yStackChanged = true;
0394         yStack.append(list);
0395         break;
0396     case DxStack:
0397         dxStackChanged = true;
0398         dxStack.append(list);
0399         break;
0400     case DyStack:
0401         dyStackChanged = true;
0402         dyStack.append(list);
0403         break;
0404     case AngleStack:
0405         angleStackChanged = true;
0406         angleStack.append(list);
0407         break;
0408     default:
0409         ASSERT_NOT_REACHED();
0410     }
0411 }
0412 
0413 void SVGCharacterLayoutInfo::addStackContent(StackType type, float value)
0414 {
0415     if (value == 0.0f) {
0416         return;
0417     }
0418 
0419     switch (type) {
0420     case BaselineShiftStack:
0421         baselineShiftStackChanged = true;
0422         baselineShiftStack.append(value);
0423         break;
0424     default:
0425         ASSERT_NOT_REACHED();
0426     }
0427 }
0428 
0429 void SVGCharacterLayoutInfo::xStackWalk()
0430 {
0431     unsigned i = 1;
0432 
0433     while (!xStack.isEmpty()) {
0434         PositionedFloatVector &cur = xStack.last();
0435         if (i + cur.position() < cur.size()) {
0436             cur.advance(i);
0437             break;
0438         }
0439 
0440         i += cur.position();
0441         xStack.removeLast();
0442         xStackChanged = false;
0443     }
0444 }
0445 
0446 void SVGCharacterLayoutInfo::yStackWalk()
0447 {
0448     unsigned i = 1;
0449 
0450     while (!yStack.isEmpty()) {
0451         PositionedFloatVector &cur = yStack.last();
0452         if (i + cur.position() < cur.size()) {
0453             cur.advance(i);
0454             break;
0455         }
0456 
0457         i += cur.position();
0458         yStack.removeLast();
0459         yStackChanged = false;
0460     }
0461 }
0462 
0463 void SVGCharacterLayoutInfo::dxStackWalk()
0464 {
0465     unsigned i = 1;
0466 
0467     while (!dxStack.isEmpty()) {
0468         PositionedFloatVector &cur = dxStack.last();
0469         if (i + cur.position() < cur.size()) {
0470             cur.advance(i);
0471             break;
0472         }
0473 
0474         i += cur.position();
0475         dxStack.removeLast();
0476         dxStackChanged = false;
0477     }
0478 }
0479 
0480 void SVGCharacterLayoutInfo::dyStackWalk()
0481 {
0482     unsigned i = 1;
0483 
0484     while (!dyStack.isEmpty()) {
0485         PositionedFloatVector &cur = dyStack.last();
0486         if (i + cur.position() < cur.size()) {
0487             cur.advance(i);
0488             break;
0489         }
0490 
0491         i += cur.position();
0492         dyStack.removeLast();
0493         dyStackChanged = false;
0494     }
0495 }
0496 
0497 void SVGCharacterLayoutInfo::angleStackWalk()
0498 {
0499     unsigned i = 1;
0500 
0501     while (!angleStack.isEmpty()) {
0502         PositionedFloatVector &cur = angleStack.last();
0503         if (i + cur.position() < cur.size()) {
0504             cur.advance(i);
0505             break;
0506         }
0507 
0508         i += cur.position();
0509         angleStack.removeLast();
0510         angleStackChanged = false;
0511     }
0512 }
0513 
0514 void SVGCharacterLayoutInfo::baselineShiftStackWalk()
0515 {
0516     if (!baselineShiftStack.isEmpty()) {
0517         baselineShiftStack.removeLast();
0518         baselineShiftStackChanged = false;
0519     }
0520 }
0521 
0522 bool SVGChar::isHidden() const
0523 {
0524     return pathData && pathData->hidden;
0525 }
0526 
0527 AffineTransform SVGChar::characterTransform() const
0528 {
0529     AffineTransform ctm;
0530 
0531     // Rotate character around angle, and possibly scale.
0532     ctm.translate(x, y);
0533     ctm.rotate(angle);
0534 
0535     if (pathData) {
0536         ctm.scale(pathData->xScale, pathData->yScale);
0537         ctm.translate(pathData->xShift, pathData->yShift);
0538         ctm.rotate(pathData->orientationAngle);
0539     }
0540 
0541     ctm.translate(orientationShiftX - x, orientationShiftY - y);
0542     return ctm;
0543 }
0544 
0545 } // namespace WebCore
0546 
0547 #endif // ENABLE(SVG)