Changeset 561 for trunk/src/svg/qsvggraphics.cpp
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/svg/qsvggraphics.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtSvg module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 57 57 QT_BEGIN_NAMESPACE 58 58 59 #define QT_SVG_DRAW_SHAPE(command) \ 60 applyStyle(p, states); \ 61 qreal oldOpacity = p->opacity(); \ 62 QBrush oldBrush = p->brush(); \ 63 QPen oldPen = p->pen(); \ 64 p->setPen(Qt::NoPen); \ 65 p->setOpacity(oldOpacity * states.fillOpacity); \ 66 command; \ 67 p->setOpacity(oldOpacity); \ 68 p->setPen(oldPen); \ 69 p->setBrush(Qt::NoBrush); \ 70 command; \ 71 p->setBrush(oldBrush); \ 72 revertStyle(p, states); 59 #define QT_SVG_DRAW_SHAPE(command) \ 60 qreal oldOpacity = p->opacity(); \ 61 QBrush oldBrush = p->brush(); \ 62 QPen oldPen = p->pen(); \ 63 p->setPen(Qt::NoPen); \ 64 p->setOpacity(oldOpacity * states.fillOpacity); \ 65 command; \ 66 p->setPen(oldPen); \ 67 if (oldPen.widthF() != 0) { \ 68 p->setOpacity(oldOpacity * states.strokeOpacity); \ 69 p->setBrush(Qt::NoBrush); \ 70 command; \ 71 p->setBrush(oldBrush); \ 72 } \ 73 p->setOpacity(oldOpacity); 73 74 74 75 … … 95 96 { 96 97 qreal sw = strokeWidth(); 97 if (qFuzzy Compare(sw + 1, 1))98 if (qFuzzyIsNull(sw)) 98 99 return m_bounds; 99 100 else { … … 106 107 void QSvgCircle::draw(QPainter *p, QSvgExtraStates &states) 107 108 { 109 applyStyle(p, states); 108 110 QT_SVG_DRAW_SHAPE(p->drawEllipse(m_bounds)); 111 revertStyle(p, states); 109 112 } 110 113 … … 118 121 { 119 122 applyStyle(p, states); 120 p->drawPath(cubic); 123 if (p->pen().widthF() != 0) { 124 qreal oldOpacity = p->opacity(); 125 p->setOpacity(oldOpacity * states.strokeOpacity); 126 p->drawPath(cubic); 127 p->setOpacity(oldOpacity); 128 } 121 129 revertStyle(p, states); 122 130 } … … 130 138 { 131 139 qreal sw = strokeWidth(); 132 if (qFuzzy Compare(sw + 1, 1))140 if (qFuzzyIsNull(sw)) 133 141 return m_bounds; 134 142 else { … … 141 149 void QSvgEllipse::draw(QPainter *p, QSvgExtraStates &states) 142 150 { 151 applyStyle(p, states); 143 152 QT_SVG_DRAW_SHAPE(p->drawEllipse(m_bounds)); 153 revertStyle(p, states); 144 154 } 145 155 … … 172 182 { 173 183 applyStyle(p, states); 174 p->drawLine(m_bounds); 184 if (p->pen().widthF() != 0) { 185 qreal oldOpacity = p->opacity(); 186 p->setOpacity(oldOpacity * states.strokeOpacity); 187 p->drawLine(m_bounds); 188 p->setOpacity(oldOpacity); 189 } 175 190 revertStyle(p, states); 176 191 } … … 179 194 : QSvgNode(parent), m_path(qpath) 180 195 { 181 //m_cachedBounds = m_path.controlPointRect();182 m_cachedBounds = m_path.boundingRect();183 196 } 184 197 185 198 void QSvgPath::draw(QPainter *p, QSvgExtraStates &states) 186 199 { 200 applyStyle(p, states); 201 m_path.setFillRule(states.fillRule); 187 202 QT_SVG_DRAW_SHAPE(p->drawPath(m_path)); 203 revertStyle(p, states); 188 204 } 189 205 … … 191 207 { 192 208 qreal sw = strokeWidth(); 193 if (qFuzzyCompare(sw + 1, 1)) 209 if (qFuzzyIsNull(sw)) { 210 if (m_cachedBounds.isNull()) 211 //m_cachedBounds = m_path.controlPointRect(); 212 m_cachedBounds = m_path.boundingRect(); 213 194 214 return m_cachedBounds; 215 } 195 216 else { 196 217 return boundsOnStroke(m_path, sw); … … 201 222 : QSvgNode(parent), m_poly(poly) 202 223 { 203 204 224 } 205 225 … … 207 227 { 208 228 qreal sw = strokeWidth(); 209 if (qFuzzy Compare(sw + 1, 1))229 if (qFuzzyIsNull(sw)) 210 230 return m_poly.boundingRect(); 211 231 else { … … 218 238 void QSvgPolygon::draw(QPainter *p, QSvgExtraStates &states) 219 239 { 220 QT_SVG_DRAW_SHAPE(p->drawPolygon(m_poly)); 240 applyStyle(p, states); 241 QT_SVG_DRAW_SHAPE(p->drawPolygon(m_poly, states.fillRule)); 242 revertStyle(p, states); 221 243 } 222 244 … … 231 253 { 232 254 applyStyle(p, states); 255 qreal oldOpacity = p->opacity(); 233 256 if (p->brush().style() != Qt::NoBrush) { 234 257 QPen save = p->pen(); 235 258 p->setPen(QPen(Qt::NoPen)); 236 p->drawPolygon(m_poly); 259 p->setOpacity(oldOpacity * states.fillOpacity); 260 p->drawPolygon(m_poly, states.fillRule); 237 261 p->setPen(save); 238 262 } 239 p->drawPolyline(m_poly); 263 if (p->pen().widthF() != 0) { 264 p->setOpacity(oldOpacity * states.strokeOpacity); 265 p->drawPolyline(m_poly); 266 } 267 p->setOpacity(oldOpacity); 240 268 revertStyle(p, states); 241 269 } … … 250 278 { 251 279 qreal sw = strokeWidth(); 252 if (qFuzzy Compare(sw + 1, 1))280 if (qFuzzyIsNull(sw)) 253 281 return m_rect; 254 282 else { … … 261 289 void QSvgRect::draw(QPainter *p, QSvgExtraStates &states) 262 290 { 291 applyStyle(p, states); 263 292 if (m_rx || m_ry) { 264 293 QT_SVG_DRAW_SHAPE(p->drawRoundedRect(m_rect, m_rx, m_ry, Qt::RelativeSize)); … … 266 295 QT_SVG_DRAW_SHAPE(p->drawRect(m_rect)); 267 296 } 268 } 297 revertStyle(p, states); 298 } 299 300 QSvgTspan * const QSvgText::LINEBREAK = 0; 269 301 270 302 QSvgText::QSvgText(QSvgNode *parent, const QPointF &coord) 271 303 : QSvgNode(parent) 272 304 , m_coord(coord) 273 , m_textAlignment(Qt::AlignLeft)274 , m_scale(1)275 , m_appendSpace(false)276 305 , m_type(TEXT) 277 306 , m_size(0, 0) 278 { 279 m_paragraphs.push_back(QString()); 280 m_formatRanges.push_back(QList<QTextLayout::FormatRange>()); 307 , m_mode(Default) 308 { 281 309 } 282 310 283 311 QSvgText::~QSvgText() 284 312 { 313 for (int i = 0; i < m_tspans.size(); ++i) { 314 if (m_tspans[i] != LINEBREAK) 315 delete m_tspans[i]; 316 } 285 317 } 286 318 … … 296 328 { 297 329 applyStyle(p, states); 298 299 QSvgFontStyle *fontStyle = static_cast<QSvgFontStyle*>( 300 styleProperty(QSvgStyleProperty::FONT)); 301 if (fontStyle && fontStyle->svgFont()) { 302 // SVG fonts not fully supported... 303 QString text = m_paragraphs.front(); 304 for (int i = 1; i < m_paragraphs.size(); ++i) { 305 text.append(QLatin1Char('\n')); 306 text.append(m_paragraphs[i]); 307 } 308 fontStyle->svgFont()->draw(p, m_coord, text, fontStyle->pointSize(), m_textAlignment); 309 revertStyle(p, states); 310 return; 311 } 312 313 // Scale the font to its correct size. 330 qreal oldOpacity = p->opacity(); 331 p->setOpacity(oldOpacity * states.fillOpacity); 332 333 // Force the font to have a size of 100 pixels to avoid truncation problems 334 // when the font is very small. 335 qreal scale = 100.0 / p->font().pointSizeF(); 336 Qt::Alignment alignment = states.textAnchor; 337 314 338 QTransform oldTransform = p->worldTransform(); 315 p->scale(1 / m_scale, 1 / m_scale);339 p->scale(1 / scale, 1 / scale); 316 340 317 341 qreal y = 0; 318 342 bool initial = true; 319 qreal px = m_coord.x() * m_scale;320 qreal py = m_coord.y() * m_scale;321 QSizeF scaledSize = m_size * m_scale;343 qreal px = m_coord.x() * scale; 344 qreal py = m_coord.y() * scale; 345 QSizeF scaledSize = m_size * scale; 322 346 323 347 if (m_type == TEXTAREA) { 324 if ( m_textAlignment == Qt::AlignHCenter)348 if (alignment == Qt::AlignHCenter) 325 349 px += scaledSize.width() / 2; 326 else if ( m_textAlignment == Qt::AlignRight)350 else if (alignment == Qt::AlignRight) 327 351 px += scaledSize.width(); 328 352 } … … 330 354 QRectF bounds; 331 355 if (m_size.height() != 0) 332 bounds = QRectF(0, 0, 1, scaledSize.height()); 333 334 for (int i = 0; i < m_paragraphs.size(); ++i) { 335 QTextLayout tl(m_paragraphs[i]); 336 QTextOption op = tl.textOption(); 337 op.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); 338 tl.setTextOption(op); 339 tl.setAdditionalFormats(m_formatRanges[i]); 340 tl.beginLayout(); 341 forever { 342 QTextLine line = tl.createLine(); 343 if (!line.isValid()) 356 bounds = QRectF(0, py, 1, scaledSize.height()); // x and width are not used. 357 358 bool appendSpace = false; 359 QVector<QString> paragraphs; 360 QStack<QTextCharFormat> formats; 361 QVector<QList<QTextLayout::FormatRange> > formatRanges; 362 paragraphs.push_back(QString()); 363 formatRanges.push_back(QList<QTextLayout::FormatRange>()); 364 365 for (int i = 0; i < m_tspans.size(); ++i) { 366 if (m_tspans[i] == LINEBREAK) { 367 if (m_type == TEXTAREA) { 368 if (paragraphs.back().isEmpty()) { 369 QFont font = p->font(); 370 font.setPixelSize(font.pointSizeF() * scale); 371 372 QTextLayout::FormatRange range; 373 range.start = 0; 374 range.length = 1; 375 range.format.setFont(font); 376 formatRanges.back().append(range); 377 378 paragraphs.back().append(QLatin1Char(' '));; 379 } 380 appendSpace = false; 381 paragraphs.push_back(QString()); 382 formatRanges.push_back(QList<QTextLayout::FormatRange>()); 383 } 384 } else { 385 WhitespaceMode mode = m_tspans[i]->whitespaceMode(); 386 m_tspans[i]->applyStyle(p, states); 387 388 QFont font = p->font(); 389 font.setPixelSize(font.pointSizeF() * scale); 390 391 QString newText(m_tspans[i]->text()); 392 newText.replace(QLatin1Char('\t'), QLatin1Char(' ')); 393 newText.replace(QLatin1Char('\n'), QLatin1Char(' ')); 394 395 bool prependSpace = !appendSpace && !m_tspans[i]->isTspan() && (mode == Default) && !paragraphs.back().isEmpty() && newText.startsWith(QLatin1Char(' ')); 396 if (appendSpace || prependSpace) 397 paragraphs.back().append(QLatin1Char(' ')); 398 399 bool appendSpaceNext = (!m_tspans[i]->isTspan() && (mode == Default) && newText.endsWith(QLatin1Char(' '))); 400 401 if (mode == Default) { 402 newText = newText.simplified(); 403 if (newText.isEmpty()) 404 appendSpaceNext = false; 405 } 406 407 QTextLayout::FormatRange range; 408 range.start = paragraphs.back().length(); 409 range.length = newText.length(); 410 range.format.setFont(font); 411 range.format.setTextOutline(p->pen()); 412 range.format.setForeground(p->brush()); 413 414 if (appendSpace) { 415 Q_ASSERT(!formatRanges.back().isEmpty()); 416 ++formatRanges.back().back().length; 417 } else if (prependSpace) { 418 --range.start; 419 ++range.length; 420 } 421 formatRanges.back().append(range); 422 423 appendSpace = appendSpaceNext; 424 paragraphs.back() += newText; 425 426 m_tspans[i]->revertStyle(p, states); 427 } 428 } 429 430 if (states.svgFont) { 431 // SVG fonts not fully supported... 432 QString text = paragraphs.front(); 433 for (int i = 1; i < paragraphs.size(); ++i) { 434 text.append(QLatin1Char('\n')); 435 text.append(paragraphs[i]); 436 } 437 states.svgFont->draw(p, m_coord * scale, text, p->font().pointSizeF() * scale, states.textAnchor); 438 } else { 439 for (int i = 0; i < paragraphs.size(); ++i) { 440 QTextLayout tl(paragraphs[i]); 441 QTextOption op = tl.textOption(); 442 op.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); 443 tl.setTextOption(op); 444 tl.setAdditionalFormats(formatRanges[i]); 445 tl.beginLayout(); 446 447 forever { 448 QTextLine line = tl.createLine(); 449 if (!line.isValid()) 450 break; 451 if (m_size.width() != 0) 452 line.setLineWidth(scaledSize.width()); 453 } 454 tl.endLayout(); 455 456 bool endOfBoundsReached = false; 457 for (int i = 0; i < tl.lineCount(); ++i) { 458 QTextLine line = tl.lineAt(i); 459 460 qreal x = 0; 461 if (alignment == Qt::AlignHCenter) 462 x -= 0.5 * line.naturalTextWidth(); 463 else if (alignment == Qt::AlignRight) 464 x -= line.naturalTextWidth(); 465 466 if (initial && m_type == TEXT) 467 y -= line.ascent(); 468 initial = false; 469 470 line.setPosition(QPointF(x, y)); 471 472 // Check if the current line fits into the bounding rectangle. 473 if ((m_size.width() != 0 && line.naturalTextWidth() > scaledSize.width()) 474 || (m_size.height() != 0 && y + line.height() > scaledSize.height())) { 475 // I need to set the bounds height to 'y-epsilon' to avoid drawing the current 476 // line. Since the font is scaled to 100 units, 1 should be a safe epsilon. 477 bounds.setHeight(y - 1); 478 endOfBoundsReached = true; 479 break; 480 } 481 482 y += 1.1 * line.height(); 483 } 484 tl.draw(p, QPointF(px, py), QVector<QTextLayout::FormatRange>(), bounds); 485 486 if (endOfBoundsReached) 344 487 break; 345 346 if (m_size.width() != 0)347 line.setLineWidth(scaledSize.width());348 488 } 349 tl.endLayout();350 351 bool endOfBoundsReached = false;352 for (int i = 0; i < tl.lineCount(); ++i) {353 QTextLine line = tl.lineAt(i);354 355 qreal x = 0;356 if (m_textAlignment == Qt::AlignHCenter)357 x -= line.naturalTextWidth() / 2;358 else if (m_textAlignment == Qt::AlignRight)359 x -= line.naturalTextWidth();360 361 if (initial && m_type == TEXT)362 y -= line.ascent();363 initial = false;364 365 line.setPosition(QPointF(x, y));366 if ((m_size.width() != 0 && line.naturalTextWidth() > scaledSize.width())367 || (m_size.height() != 0 && y + line.height() > scaledSize.height())) {368 bounds.setHeight(y);369 endOfBoundsReached = true;370 break;371 }372 373 y += 1.1 * line.height();374 }375 tl.draw(p, QPointF(px, py), QVector<QTextLayout::FormatRange>(), bounds);376 377 if (endOfBoundsReached)378 break;379 489 } 380 490 381 491 p->setWorldTransform(oldTransform, false); 382 revertStyle(p, states); 383 } 384 385 void QSvgText::insertText(const QString &text, WhitespaceMode mode) 386 { 387 bool isTSpan = (m_formats.count() == 2); 388 QString newText(text); 389 newText.replace(QLatin1Char('\t'), QLatin1Char(' ')); 390 newText.replace(QLatin1Char('\n'), QLatin1Char(' ')); 391 392 bool prependSpace = !m_appendSpace && !isTSpan && (mode == Default) && !m_paragraphs.back().isEmpty() && newText.startsWith(QLatin1Char(' ')); 393 if (m_appendSpace || prependSpace) 394 m_paragraphs.back().append(QLatin1Char(' ')); 395 396 bool appendSpaceNext = (!isTSpan && (mode == Default) && newText.endsWith(QLatin1Char(' '))); 397 398 if (mode == Default) { 399 newText = newText.simplified(); 400 if (newText.isEmpty()) 401 appendSpaceNext = false; 402 } 403 404 if (!m_formats.isEmpty()) { 405 QTextLayout::FormatRange range; 406 range.start = m_paragraphs.back().length(); 407 range.length = newText.length(); 408 range.format = m_formats.top(); 409 if (m_appendSpace) { 410 Q_ASSERT(!m_formatRanges.back().isEmpty()); 411 ++m_formatRanges.back().back().length; 412 } else if (prependSpace) { 413 --range.start; 414 ++range.length; 415 } 416 m_formatRanges.back().append(range); 417 } 418 419 m_appendSpace = appendSpaceNext; 420 m_paragraphs.back() += newText; 421 } 422 423 void QSvgText::insertFormat(const QTextCharFormat &format) 424 { 425 QTextCharFormat mergedFormat = format; 426 if (!m_formats.isEmpty()) { 427 mergedFormat = m_formats.top(); 428 mergedFormat.merge(format); 429 } 430 m_formats.push(mergedFormat); 431 } 432 433 void QSvgText::insertLineBreak() 434 { 435 if (m_type == TEXTAREA) { 436 if (m_paragraphs.back().isEmpty()) 437 insertText(QLatin1String(" "), Preserve); 438 m_appendSpace = false; 439 m_paragraphs.push_back(QString()); 440 m_formatRanges.push_back(QList<QTextLayout::FormatRange>()); 441 } 442 } 443 444 void QSvgText::popFormat() 445 { 446 if (m_formats.count() > 1) 447 m_formats.pop(); 448 } 449 450 qreal QSvgText::scale() const 451 { 452 return m_scale; 453 } 454 455 void QSvgText::setScale(qreal scale) 456 { 457 m_scale = scale; 458 } 459 460 const QTextCharFormat &QSvgText::topFormat() const 461 { 462 return m_formats.top(); 463 } 464 465 void QSvgText::setTextAlignment(const Qt::Alignment &alignment) 466 { 467 m_textAlignment = alignment; 492 p->setOpacity(oldOpacity); 493 revertStyle(p, states); 494 } 495 496 void QSvgText::addText(const QString &text) 497 { 498 m_tspans.append(new QSvgTspan(this, false)); 499 m_tspans.back()->setWhitespaceMode(m_mode); 500 m_tspans.back()->addText(text); 468 501 } 469 502 … … 597 630 { 598 631 qreal sw = strokeWidth(); 599 if (qFuzzy Compare(sw + 1, 1))632 if (qFuzzyIsNull(sw)) 600 633 return m_poly.boundingRect(); 601 634 else { … … 609 642 { 610 643 qreal sw = strokeWidth(); 611 if (qFuzzy Compare(sw + 1, 1))644 if (qFuzzyIsNull(sw)) 612 645 return m_cachedBounds; 613 646 else { … … 624 657 { 625 658 qreal sw = strokeWidth(); 626 if (qFuzzy Compare(sw + 1, 1)) {659 if (qFuzzyIsNull(sw)) { 627 660 qreal minX = qMin(m_bounds.x1(), m_bounds.x2()); 628 661 qreal minY = qMin(m_bounds.y1(), m_bounds.y2());
Note:
See TracChangeset
for help on using the changeset viewer.