File indexing completed on 2024-04-28 15:24:19
0001 /** 0002 * This file is part of the DOM implementation for KDE. 0003 * 0004 * Copyright (C) 2007 Rob Buis <buis@kde.org> 0005 * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> 0006 * 0007 * This library is free software; you can redistribute it and/or 0008 * modify it under the terms of the GNU Library General Public 0009 * License as published by the Free Software Foundation; either 0010 * version 2 of the License, or (at your option) any later version. 0011 * 0012 * This library is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 * Library General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU Library General Public License 0018 * along with this library; see the file COPYING.LIB. If not, write to 0019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 * Boston, MA 02110-1301, USA. 0021 * 0022 */ 0023 0024 #include "wtf/Platform.h" 0025 0026 #if ENABLE(SVG) 0027 #include "SVGInlineTextBox.h" 0028 0029 #include "Document.h" 0030 /*#include "Editor.h" 0031 #include "Frame.h" 0032 #include "GraphicsContext.h" 0033 #include "InlineFlowBox.h" 0034 #include "Range.h"*/ 0035 #include "SVGPaintServer.h" 0036 #include "SVGRootInlineBox.h" 0037 /*#include "Text.h"*/ 0038 #include "render_line.h" 0039 0040 #include <float.h> 0041 #include <math.h> 0042 0043 using std::max; 0044 0045 namespace WebCore 0046 { 0047 0048 SVGInlineTextBox::SVGInlineTextBox(RenderObject *obj) 0049 : InlineTextBox(obj) 0050 { 0051 } 0052 0053 int SVGInlineTextBox::selectionTop() 0054 { 0055 return m_y; 0056 } 0057 0058 int SVGInlineTextBox::selectionHeight() 0059 { 0060 return m_height; 0061 } 0062 0063 SVGRootInlineBox *SVGInlineTextBox::svgRootInlineBox() const 0064 { 0065 // qCDebug(KHTML_LOG) << "find inline box"; 0066 // Find associated root inline box 0067 InlineFlowBox *parentBox = parent(); 0068 0069 while (parentBox && !parentBox->isRootInlineBox()) { 0070 parentBox = parentBox->parent(); 0071 } 0072 0073 ASSERT(parentBox); 0074 ASSERT(parentBox->isRootInlineBox()); 0075 0076 if (!parentBox->isSVGRootInlineBox()) { 0077 return nullptr; 0078 } 0079 0080 return static_cast<SVGRootInlineBox *>(parentBox); 0081 } 0082 0083 float SVGInlineTextBox::calculateGlyphWidth(RenderStyle *style, int offset, int extraCharsAvailable, int &charsConsumed, String &glyphName) const 0084 { 0085 ASSERT(style); 0086 return style->htmlFont().floatWidth(renderText()->text(), offset, 1, extraCharsAvailable, charsConsumed, glyphName); 0087 //return style->htmlFont().floatWidth(svgTextRunForInlineTextBox(renderText()->text() + offset, 1, style, this, 0), extraCharsAvailable, charsConsumed, glyphName); 0088 } 0089 0090 float SVGInlineTextBox::calculateGlyphHeight(RenderStyle *style, int offset, int extraCharsAvailable) const 0091 { 0092 Q_UNUSED(offset); 0093 Q_UNUSED(extraCharsAvailable); 0094 ASSERT(style); 0095 0096 // This is just a guess, and the only purpose of this function is to centralize this hack. 0097 // In real-life top-top-bottom scripts this won't be enough, I fear. 0098 return style->htmlFont().ascent() + style->htmlFont().descent(); 0099 } 0100 0101 FloatRect SVGInlineTextBox::calculateGlyphBoundaries(RenderStyle *style, int offset, const SVGChar &svgChar) const 0102 { 0103 const Font &font = style->htmlFont(); 0104 0105 // Take RTL text into account and pick right glyph width/height. 0106 float glyphWidth = 0.0f; 0107 0108 // FIXME: account for multi-character glyphs 0109 int charsConsumed; 0110 String glyphName; 0111 if (!m_reversed) { 0112 glyphWidth = calculateGlyphWidth(style, offset, 0, charsConsumed, glyphName); 0113 } else { 0114 glyphWidth = calculateGlyphWidth(style, start() + end() - offset, 0, charsConsumed, glyphName); 0115 } 0116 0117 float x1 = svgChar.x; 0118 float x2 = svgChar.x + glyphWidth; 0119 0120 float y1 = svgChar.y - font.ascent(); 0121 float y2 = svgChar.y + font.descent(); 0122 0123 FloatRect glyphRect(x1, y1, x2 - x1, y2 - y1); 0124 0125 // Take per-character transformations into account 0126 AffineTransform ctm = svgChar.characterTransform(); 0127 if (!ctm.isIdentity()) { 0128 glyphRect = ctm.mapRect(glyphRect); 0129 } 0130 0131 return glyphRect; 0132 } 0133 0134 // Helper class for closestCharacterToPosition() 0135 struct SVGInlineTextBoxClosestCharacterToPositionWalker { 0136 SVGInlineTextBoxClosestCharacterToPositionWalker(int x, int y) 0137 : m_character(nullptr) 0138 , m_distance(FLT_MAX) 0139 , m_x(x) 0140 , m_y(y) 0141 , m_offset(0) 0142 { 0143 } 0144 0145 void chunkPortionCallback(SVGInlineTextBox *textBox, int startOffset, const AffineTransform &chunkCtm, 0146 const Vector<SVGChar>::iterator &start, const Vector<SVGChar>::iterator &end) 0147 { 0148 RenderStyle *style = textBox->renderText()->style(); 0149 0150 Vector<SVGChar>::iterator closestCharacter = nullptr; 0151 unsigned int closestOffset = UINT_MAX; 0152 0153 for (Vector<SVGChar>::iterator it = start; it != end; ++it) { 0154 if (it->isHidden()) { 0155 continue; 0156 } 0157 0158 unsigned int newOffset = textBox->start() + (it - start) + startOffset; 0159 FloatRect glyphRect = chunkCtm.mapRect(textBox->calculateGlyphBoundaries(style, newOffset, *it)); 0160 0161 // Take RTL text into account and pick right glyph width/height. 0162 // NOTE: This offset has to be corrected _after_ calling calculateGlyphBoundaries 0163 if (textBox->m_reversed) { 0164 newOffset = textBox->start() + textBox->end() - newOffset; 0165 } 0166 0167 // Calculate distances relative to the glyph mid-point. I hope this is accurate enough. 0168 float xDistance = glyphRect.x() + glyphRect.width() / 2.0f - m_x; 0169 float yDistance = glyphRect.y() - glyphRect.height() / 2.0f - m_y; 0170 0171 float newDistance = sqrtf(xDistance * xDistance + yDistance * yDistance); 0172 if (newDistance <= m_distance) { 0173 m_distance = newDistance; 0174 closestOffset = newOffset; 0175 closestCharacter = it; 0176 } 0177 } 0178 0179 if (closestOffset != UINT_MAX) { 0180 // Record current chunk, if it contains the current closest character next to the mouse. 0181 m_character = closestCharacter; 0182 m_offset = closestOffset; 0183 } 0184 } 0185 0186 SVGChar *character() const 0187 { 0188 return m_character; 0189 } 0190 0191 int offset() const 0192 { 0193 if (!m_character) { 0194 return 0; 0195 } 0196 0197 return m_offset; 0198 } 0199 0200 private: 0201 Vector<SVGChar>::iterator m_character; 0202 float m_distance; 0203 0204 int m_x; 0205 int m_y; 0206 int m_offset; 0207 }; 0208 0209 // Helper class for selectionRect() 0210 struct SVGInlineTextBoxSelectionRectWalker { 0211 SVGInlineTextBoxSelectionRectWalker() 0212 { 0213 } 0214 0215 void chunkPortionCallback(SVGInlineTextBox *textBox, int startOffset, const AffineTransform &chunkCtm, 0216 const Vector<SVGChar>::iterator &start, const Vector<SVGChar>::iterator &end) 0217 { 0218 RenderStyle *style = textBox->renderText()->style(); 0219 0220 for (Vector<SVGChar>::iterator it = start; it != end; ++it) { 0221 if (it->isHidden()) { 0222 continue; 0223 } 0224 0225 unsigned int newOffset = textBox->start() + (it - start) + startOffset; 0226 m_selectionRect.unite(textBox->calculateGlyphBoundaries(style, newOffset, *it)); 0227 } 0228 0229 m_selectionRect = chunkCtm.mapRect(m_selectionRect); 0230 } 0231 0232 FloatRect selectionRect() const 0233 { 0234 return m_selectionRect; 0235 } 0236 0237 private: 0238 FloatRect m_selectionRect; 0239 }; 0240 0241 SVGChar *SVGInlineTextBox::closestCharacterToPosition(int x, int y, int &offset) const 0242 { 0243 SVGRootInlineBox *rootBox = svgRootInlineBox(); 0244 if (!rootBox) { 0245 return nullptr; 0246 } 0247 0248 SVGInlineTextBoxClosestCharacterToPositionWalker walkerCallback(x, y); 0249 SVGTextChunkWalker<SVGInlineTextBoxClosestCharacterToPositionWalker> walker(&walkerCallback, &SVGInlineTextBoxClosestCharacterToPositionWalker::chunkPortionCallback); 0250 0251 rootBox->walkTextChunks(&walker, this); 0252 0253 offset = walkerCallback.offset(); 0254 return walkerCallback.character(); 0255 } 0256 0257 bool SVGInlineTextBox::svgCharacterHitsPosition(int x, int y, int &offset) const 0258 { 0259 SVGChar *charAtPosPtr = closestCharacterToPosition(x, y, offset); 0260 if (!charAtPosPtr) { 0261 return false; 0262 } 0263 0264 SVGChar &charAtPos = *charAtPosPtr; 0265 RenderStyle *style = renderText()->style(m_firstLine); 0266 FloatRect glyphRect = calculateGlyphBoundaries(style, offset, charAtPos); 0267 0268 if (m_reversed) { 0269 offset++; 0270 } 0271 0272 // FIXME: todo list 0273 // (#13910) This code does not handle bottom-to-top/top-to-bottom vertical text. 0274 0275 // Check whether y position hits the current character 0276 if (y < charAtPos.y - glyphRect.height() || y > charAtPos.y) { 0277 return false; 0278 } 0279 0280 // Check whether x position hits the current character 0281 if (x < charAtPos.x) { 0282 if (offset > 0 && !m_reversed) { 0283 return true; 0284 } else if (offset < (int) end() && m_reversed) { 0285 return true; 0286 } 0287 0288 return false; 0289 } 0290 0291 // If we are past the last glyph of this box, don't mark it as 'hit' anymore. 0292 if (x >= charAtPos.x + glyphRect.width() && offset == (int) end()) { 0293 return false; 0294 } 0295 0296 // Snap to character at half of it's advance 0297 if (x >= charAtPos.x + glyphRect.width() / 2.0) { 0298 offset += m_reversed ? -1 : 1; 0299 } 0300 0301 return true; 0302 } 0303 0304 int SVGInlineTextBox::offsetForPosition(int x, bool includePartialGlyphs) const 0305 { 0306 Q_UNUSED(x); 0307 Q_UNUSED(includePartialGlyphs); 0308 // SVG doesn't use the offset <-> position selection system. 0309 ASSERT_NOT_REACHED(); 0310 return 0; 0311 } 0312 0313 int SVGInlineTextBox::positionForOffset(int offset) const 0314 { 0315 Q_UNUSED(offset); 0316 // SVG doesn't use the offset <-> position selection system. 0317 ASSERT_NOT_REACHED(); 0318 return 0; 0319 } 0320 0321 /*bool SVGInlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty) 0322 { 0323 ASSERT(!isLineBreak()); 0324 0325 IntRect rect = selectionRect(0, 0, 0, len()); 0326 if (object()->style()->visibility() == VISIBLE && rect.contains(x, y)) { 0327 object()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); 0328 return true; 0329 } 0330 0331 return false; 0332 }*/ 0333 0334 IntRect SVGInlineTextBox::selectionRect(int, int, int startPos, int endPos) 0335 { 0336 if (startPos >= endPos) { 0337 return IntRect(); 0338 } 0339 0340 // TODO: Actually respect startPos/endPos - we're returning the _full_ selectionRect 0341 // here. This won't lead to visible bugs, but to extra work being done. Investigate. 0342 SVGRootInlineBox *rootBox = svgRootInlineBox(); 0343 if (!rootBox) { 0344 return IntRect(); 0345 } 0346 0347 SVGInlineTextBoxSelectionRectWalker walkerCallback; 0348 SVGTextChunkWalker<SVGInlineTextBoxSelectionRectWalker> walker(&walkerCallback, &SVGInlineTextBoxSelectionRectWalker::chunkPortionCallback); 0349 0350 rootBox->walkTextChunks(&walker, this); 0351 return enclosingIntRect(walkerCallback.selectionRect()); 0352 } 0353 0354 void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo &paintInfo, int tx, int ty, const SVGChar &svgChar, const UChar *chars, int length, SVGPaintServer *activePaintServer) 0355 { 0356 Q_UNUSED(tx); 0357 Q_UNUSED(ty); 0358 Q_UNUSED(chars); 0359 Q_UNUSED(length); 0360 Q_UNUSED(activePaintServer); 0361 // qCDebug(KHTML_LOG) << "paint character"; 0362 /*FIXME khtml if (object()->style()->visibility() != VISIBLE || paintInfo.phase == PaintPhaseOutline) 0363 return; 0364 0365 ASSERT(paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines);*/ 0366 0367 RenderText *text = renderText(); 0368 ASSERT(text); 0369 0370 // Determine whether or not we're selected. 0371 bool haveSelection = text->selectionState() != RenderObject::SelectionNone; 0372 if (!haveSelection && paintInfo.phase == PaintActionSelection) 0373 // When only painting the selection, don't bother to paint if there is none. 0374 { 0375 return; 0376 } 0377 0378 // Determine whether or not we have a composition. 0379 /*bool containsComposition = text->document()->frame()->editor()->compositionNode() == text->node(); 0380 bool useCustomUnderlines = containsComposition && text->document()->frame()->editor()->compositionUsesCustomUnderlines();*/ 0381 0382 // Set our font 0383 RenderStyle *styleToUse = text->style(m_firstLine); 0384 const Font *font = &styleToUse->htmlFont(); 0385 if (styleToUse->font() != paintInfo.p->font()) { 0386 paintInfo.p->setFont(styleToUse->font()); 0387 } 0388 0389 AffineTransform ctm = svgChar.characterTransform(); 0390 if (!ctm.isIdentity()) { 0391 paintInfo.p->setWorldMatrix(ctm, true); 0392 } 0393 //paintInfo.context->concatCTM(ctm); 0394 0395 // 1. Paint backgrounds behind text if needed. Examples of such backgrounds include selection 0396 // and marked text. 0397 if (true/*paintInfo.phase != PaintPhaseSelection && !isPrinting*/) { 0398 #if PLATFORM(MAC) 0399 // Custom highlighters go behind everything else. 0400 if (styleToUse->highlight() != nullAtom && !paintInfo.context->paintingDisabled()) { 0401 paintCustomHighlight(tx, ty, styleToUse->highlight()); 0402 } 0403 #endif 0404 0405 /*FIXME khtml if (containsComposition && !useCustomUnderlines) 0406 paintCompositionBackground(paintInfo.context, tx, ty, styleToUse, font, 0407 text->document()->frame()->editor()->compositionStart(), 0408 text->document()->frame()->editor()->compositionEnd()); 0409 0410 paintDocumentMarkers(paintInfo.context, tx, ty, styleToUse, font, true);*/ 0411 0412 /*if (haveSelection && !useCustomUnderlines) { 0413 int boxStartOffset = chars - text->characters() - start(); 0414 //FIXME khtml paintSelection(boxStartOffset, svgChar, chars, length, paintInfo.context, styleToUse, font); 0415 }*/ 0416 } 0417 0418 // Set a text shadow if we have one. 0419 // FIXME: Support multiple shadow effects. Need more from the CG API before 0420 // we can do this. 0421 //bool setShadow = false; 0422 if (styleToUse->textShadow()) { 0423 /*FIXME khtml paintInfo.context->setShadow(IntSize(styleToUse->textShadow()->x, styleToUse->textShadow()->y), 0424 styleToUse->textShadow()->blur, styleToUse->textShadow()->color); 0425 setShadow = true;*/ 0426 } 0427 0428 IntPoint origin((int) svgChar.x, (int) svgChar.y); 0429 // qCDebug(KHTML_LOG) << "origin: " << svgChar.x << svgChar.y; 0430 //TextRun run = svgTextRunForInlineTextBox(chars, length, styleToUse, this, svgChar.x); 0431 0432 #if ENABLE(SVG_FONTS) 0433 // SVG Fonts need access to the paint server used to draw the current text chunk. 0434 // They need to be able to call renderPath() on a SVGPaintServer object. 0435 //FIXME khtml run.setActivePaintServer(activePaintServer); 0436 #endif 0437 0438 //FIXME khtml paintInfo.context->drawText(run, origin); 0439 // qCDebug(KHTML_LOG) << "font size:" << font->getFontDef().size; 0440 // qCDebug(KHTML_LOG) << "text:" << QString::fromRawData(renderText()->string()->s + m_start, m_len); 0441 0442 font->drawText(paintInfo.p, svgChar.x, svgChar.y, renderText()->string()->s, renderText()->string()->l, m_start, m_len, 0443 m_toAdd, m_reversed ? Qt::RightToLeft : Qt::LeftToRight); 0444 0445 if (true/*paintInfo.phase != PaintPhaseSelection*/) { 0446 //FIXME khtml paintDocumentMarkers(paintInfo.context, tx, ty, styleToUse, font, false); 0447 0448 /*if (useCustomUnderlines) { 0449 const Vector<CompositionUnderline>& underlines = text->document()->frame()->editor()->customCompositionUnderlines(); 0450 size_t numUnderlines = underlines.size(); 0451 0452 for (size_t index = 0; index < numUnderlines; ++index) { 0453 const CompositionUnderline& underline = underlines[index]; 0454 0455 if (underline.endOffset <= start()) 0456 // underline is completely before this run. This might be an underline that sits 0457 // before the first run we draw, or underlines that were within runs we skipped 0458 // due to truncation. 0459 continue; 0460 0461 if (underline.startOffset <= end()) { 0462 // underline intersects this run. Paint it. 0463 //FIXME khtml paintCompositionUnderline(paintInfo.context, tx, ty, underline); 0464 if (underline.endOffset > end() + 1) 0465 // underline also runs into the next run. Bail now, no more marker advancement. 0466 break; 0467 } else 0468 // underline is completely after this run, bail. A later run will paint it. 0469 break; 0470 } 0471 }*/ 0472 0473 } 0474 0475 /*if (setShadow) 0476 paintInfo.context->clearShadow();*/ 0477 0478 if (!ctm.isIdentity()) { 0479 paintInfo.p->setWorldMatrix(ctm.inverse(), true); 0480 } 0481 //paintInfo.context->concatCTM(ctm.inverse()); 0482 } 0483 0484 void SVGInlineTextBox::paintSelection(int boxStartOffset, const SVGChar &svgChar, const UChar *chars, int length, khtml::RenderObject::PaintInfo &p, RenderStyle *style, const Font *f) 0485 { 0486 Q_UNUSED(boxStartOffset); 0487 Q_UNUSED(svgChar); 0488 Q_UNUSED(chars); 0489 Q_UNUSED(length); 0490 Q_UNUSED(p); 0491 Q_UNUSED(style); 0492 Q_UNUSED(f); 0493 /*if (selectionState() == RenderObject::SelectionNone) 0494 return; 0495 0496 int startPos, endPos; 0497 selectionStartEnd(startPos, endPos); 0498 0499 if (startPos >= endPos) 0500 return; 0501 0502 Color textColor = style->color(); 0503 Color color = object()->selectionBackgroundColor(); 0504 if (!color.isValid() || color.alpha() == 0) 0505 return; 0506 0507 // If the text color ends up being the same as the selection background, invert the selection 0508 // background. This should basically never happen, since the selection has transparency. 0509 if (textColor == color) 0510 color = Color(0xff - color.red(), 0xff - color.green(), 0xff - color.blue()); 0511 0512 // Map from text box positions and a given start offset to chunk positions 0513 // 'boxStartOffset' represents the beginning of the text chunk. 0514 if ((startPos > boxStartOffset && endPos > boxStartOffset + length) || boxStartOffset >= endPos) 0515 return; 0516 0517 if (endPos > boxStartOffset + length) 0518 endPos = boxStartOffset + length; 0519 0520 if (startPos < boxStartOffset) 0521 startPos = boxStartOffset; 0522 0523 ASSERT(startPos >= boxStartOffset); 0524 ASSERT(endPos <= boxStartOffset + length); 0525 ASSERT(startPos < endPos); 0526 0527 p->save(); 0528 0529 int adjust = startPos >= boxStartOffset ? boxStartOffset : 0; 0530 p->drawHighlightForText(svgTextRunForInlineTextBox(textObject()->text()->characters() + start() + boxStartOffset, length, style, this, svgChar.x), 0531 IntPoint((int) svgChar.x, (int) svgChar.y - f->ascent()), 0532 f->ascent() + f->descent(), color, startPos - adjust, endPos - adjust); 0533 0534 p->restore();*/ 0535 } 0536 0537 static inline Path pathForDecoration(ETextDecoration decoration, RenderObject *object, float x, float y, float width) 0538 { 0539 Q_UNUSED(decoration); 0540 0541 float thickness = SVGRenderStyle::cssPrimitiveToLength(object, object->style()->svgStyle()->strokeWidth(), 1.0f); 0542 0543 const Font &font = object->style()->htmlFont(); 0544 thickness = max(thickness * powf(font.getFontDef().size, 2.0f) / font.unitsPerEm(), 1.0f); 0545 0546 if (decoration == UNDERLINE) { 0547 y += thickness * 1.5f; // For compatibility with Batik/Opera 0548 } else if (decoration == OVERLINE) { 0549 y += thickness; 0550 } 0551 0552 float halfThickness = thickness / 2.0f; 0553 return Path::createRectangle(FloatRect(x + halfThickness, y, width - 2.0f * halfThickness, thickness)); 0554 } 0555 0556 void SVGInlineTextBox::paintDecoration(ETextDecoration decoration, khtml::RenderObject::PaintInfo &pI, int tx, int ty, int width, const SVGChar &svgChar, const SVGTextDecorationInfo &info) 0557 { 0558 Q_UNUSED(decoration); 0559 Q_UNUSED(pI); 0560 Q_UNUSED(tx); 0561 Q_UNUSED(ty); 0562 Q_UNUSED(width); 0563 Q_UNUSED(svgChar); 0564 Q_UNUSED(info); 0565 0566 /*FIXME if (object()->style()->visibility() != VISIBLE) 0567 return; 0568 0569 // This function does NOT accept combinated text decorations. It's meant to be invoked for just one. 0570 ASSERT(decoration == TDNONE || decoration == UNDERLINE || decoration == OVERLINE || decoration == LINE_THROUGH || decoration == BLINK); 0571 0572 bool isFilled = info.fillServerMap.contains(decoration); 0573 bool isStroked = info.strokeServerMap.contains(decoration); 0574 0575 if (!isFilled && !isStroked) 0576 return; 0577 0578 if (decoration == UNDERLINE) 0579 ty += m_baseline; 0580 else if (decoration == LINE_THROUGH) 0581 ty += 2 * m_baseline / 3; 0582 0583 context->save(); 0584 context->beginPath(); 0585 0586 AffineTransform ctm = svgChar.characterTransform(); 0587 if (!ctm.isIdentity()) 0588 context->concatCTM(ctm); 0589 0590 if (isFilled) { 0591 if (RenderObject* fillObject = info.fillServerMap.get(decoration)) { 0592 if (SVGPaintServer* fillPaintServer = SVGPaintServer::fillPaintServer(fillObject->style(), fillObject)) { 0593 context->addPath(pathForDecoration(decoration, fillObject, tx, ty, width)); 0594 fillPaintServer->draw(context, fillObject, ApplyToFillTargetType); 0595 } 0596 } 0597 } 0598 0599 if (isStroked) { 0600 if (RenderObject* strokeObject = info.strokeServerMap.get(decoration)) { 0601 if (SVGPaintServer* strokePaintServer = SVGPaintServer::strokePaintServer(strokeObject->style(), strokeObject)) { 0602 context->addPath(pathForDecoration(decoration, strokeObject, tx, ty, width)); 0603 strokePaintServer->draw(context, strokeObject, ApplyToStrokeTargetType); 0604 } 0605 } 0606 } 0607 0608 context->restore();*/ 0609 } 0610 0611 } // namespace WebCore 0612 0613 #endif