GraphicsContextQt.cpp revision 65f03d4f644ce73618e5f4f50dd694b26f55ae12
1/* 2 * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> 3 * Copyright (C) 2006 Zack Rusin <zack@kde.org> 4 * Copyright (C) 2006 George Staikos <staikos@kde.org> 5 * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org> 6 * Copyright (C) 2006 Allan Sandfeld Jensen <sandfeld@kde.org> 7 * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> 8 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 9 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). 10 * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de> 11 * Copyright (C) 2010 Sencha, Inc. 12 * 13 * All rights reserved. 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 24 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 25 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 31 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 32 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37#include "config.h" 38#include "GraphicsContext.h" 39 40#ifdef Q_WS_WIN 41#include <windows.h> 42#endif 43 44#include "AffineTransform.h" 45#include "Color.h" 46#include "ContextShadow.h" 47#include "FloatConversion.h" 48#include "Font.h" 49#include "ImageBuffer.h" 50#include "NotImplemented.h" 51#include "Path.h" 52#include "Pattern.h" 53#include "TransparencyLayer.h" 54 55#include <QBrush> 56#include <QGradient> 57#include <QPaintDevice> 58#include <QPaintEngine> 59#include <QPainter> 60#include <QPainterPath> 61#include <QPixmap> 62#include <QPolygonF> 63#include <QStack> 64#include <QVector> 65 66#ifndef M_PI 67#define M_PI 3.14159265358979323846 68#endif 69 70namespace WebCore { 71 72QPainter::CompositionMode GraphicsContext::toQtCompositionMode(CompositeOperator op) 73{ 74 switch (op) { 75 case CompositeClear: 76 return QPainter::CompositionMode_Clear; 77 case CompositeCopy: 78 return QPainter::CompositionMode_Source; 79 case CompositeSourceOver: 80 return QPainter::CompositionMode_SourceOver; 81 case CompositeSourceIn: 82 return QPainter::CompositionMode_SourceIn; 83 case CompositeSourceOut: 84 return QPainter::CompositionMode_SourceOut; 85 case CompositeSourceAtop: 86 return QPainter::CompositionMode_SourceAtop; 87 case CompositeDestinationOver: 88 return QPainter::CompositionMode_DestinationOver; 89 case CompositeDestinationIn: 90 return QPainter::CompositionMode_DestinationIn; 91 case CompositeDestinationOut: 92 return QPainter::CompositionMode_DestinationOut; 93 case CompositeDestinationAtop: 94 return QPainter::CompositionMode_DestinationAtop; 95 case CompositeXOR: 96 return QPainter::CompositionMode_Xor; 97 case CompositePlusDarker: 98 // there is no exact match, but this is the closest 99 return QPainter::CompositionMode_Darken; 100 case CompositeHighlight: 101 return QPainter::CompositionMode_SourceOver; 102 case CompositePlusLighter: 103 return QPainter::CompositionMode_Plus; 104 default: 105 ASSERT_NOT_REACHED(); 106 } 107 108 return QPainter::CompositionMode_SourceOver; 109} 110 111static inline Qt::PenCapStyle toQtLineCap(LineCap lc) 112{ 113 switch (lc) { 114 case ButtCap: 115 return Qt::FlatCap; 116 case RoundCap: 117 return Qt::RoundCap; 118 case SquareCap: 119 return Qt::SquareCap; 120 default: 121 ASSERT_NOT_REACHED(); 122 } 123 124 return Qt::FlatCap; 125} 126 127static inline Qt::PenJoinStyle toQtLineJoin(LineJoin lj) 128{ 129 switch (lj) { 130 case MiterJoin: 131 return Qt::SvgMiterJoin; 132 case RoundJoin: 133 return Qt::RoundJoin; 134 case BevelJoin: 135 return Qt::BevelJoin; 136 default: 137 ASSERT_NOT_REACHED(); 138 } 139 140 return Qt::SvgMiterJoin; 141} 142 143static Qt::PenStyle toQPenStyle(StrokeStyle style) 144{ 145 switch (style) { 146 case NoStroke: 147 return Qt::NoPen; 148 break; 149 case SolidStroke: 150 return Qt::SolidLine; 151 break; 152 case DottedStroke: 153 return Qt::DotLine; 154 break; 155 case DashedStroke: 156 return Qt::DashLine; 157 break; 158 default: 159 ASSERT_NOT_REACHED(); 160 } 161 return Qt::NoPen; 162} 163 164static inline Qt::FillRule toQtFillRule(WindRule rule) 165{ 166 switch (rule) { 167 case RULE_EVENODD: 168 return Qt::OddEvenFill; 169 case RULE_NONZERO: 170 return Qt::WindingFill; 171 default: 172 ASSERT_NOT_REACHED(); 173 } 174 return Qt::OddEvenFill; 175} 176 177class GraphicsContextPlatformPrivate : public Noncopyable { 178public: 179 GraphicsContextPlatformPrivate(QPainter*, const QColor& initialSolidColor); 180 ~GraphicsContextPlatformPrivate(); 181 182 inline QPainter* p() const 183 { 184 if (layers.isEmpty()) 185 return painter; 186 return &layers.top()->painter; 187 } 188 189 bool antiAliasingForRectsAndLines; 190 191 QStack<TransparencyLayer*> layers; 192 // Counting real layers. Required by inTransparencyLayer() calls 193 // For example, layers with valid alphaMask are not real layers 194 int layerCount; 195 196 // reuse this brush for solid color (to prevent expensive QBrush construction) 197 QBrush solidColor; 198 199 InterpolationQuality imageInterpolationQuality; 200 bool initialSmoothPixmapTransformHint; 201 202 ContextShadow shadow; 203 QStack<ContextShadow> shadowStack; 204 205 QRectF clipBoundingRect() const 206 { 207#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0) 208 return p()->clipBoundingRect(); 209#else 210 return p()->clipRegion().boundingRect(); 211#endif 212 } 213 214 void takeOwnershipOfPlatformContext() { platformContextIsOwned = true; } 215 216private: 217 QPainter* painter; 218 bool platformContextIsOwned; 219}; 220 221GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p, const QColor& initialSolidColor) 222 : antiAliasingForRectsAndLines(false) 223 , layerCount(0) 224 , solidColor(initialSolidColor) 225 , imageInterpolationQuality(InterpolationDefault) 226 , initialSmoothPixmapTransformHint(false) 227 , painter(p) 228 , platformContextIsOwned(false) 229{ 230 if (!painter) 231 return; 232 233 // Use the default the QPainter was constructed with. 234 antiAliasingForRectsAndLines = painter->testRenderHint(QPainter::Antialiasing); 235 236 // Used for default image interpolation quality. 237 initialSmoothPixmapTransformHint = painter->testRenderHint(QPainter::SmoothPixmapTransform); 238 239 painter->setRenderHint(QPainter::Antialiasing, true); 240} 241 242GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate() 243{ 244 if (!platformContextIsOwned) 245 return; 246 247 QPaintDevice* device = painter->device(); 248 painter->end(); 249 delete painter; 250 delete device; 251} 252 253void GraphicsContext::platformInit(PlatformGraphicsContext* painter) 254{ 255 m_data = new GraphicsContextPlatformPrivate(painter, fillColor()); 256 257 setPaintingDisabled(!painter); 258 259 if (!painter) 260 return; 261 262 // solidColor is initialized with the fillColor(). 263 painter->setBrush(m_data->solidColor); 264 265 QPen pen(painter->pen()); 266 pen.setColor(strokeColor()); 267 pen.setJoinStyle(toQtLineJoin(MiterJoin)); 268 painter->setPen(pen); 269} 270 271void GraphicsContext::platformDestroy() 272{ 273 while (!m_data->layers.isEmpty()) 274 endTransparencyLayer(); 275 276 delete m_data; 277} 278 279PlatformGraphicsContext* GraphicsContext::platformContext() const 280{ 281 return m_data->p(); 282} 283 284AffineTransform GraphicsContext::getCTM() const 285{ 286 const QTransform& matrix = platformContext()->combinedTransform(); 287 return AffineTransform(matrix.m11(), matrix.m12(), matrix.m21(), 288 matrix.m22(), matrix.dx(), matrix.dy()); 289} 290 291void GraphicsContext::savePlatformState() 292{ 293 if (!m_data->layers.isEmpty() && !m_data->layers.top()->alphaMask.isNull()) 294 ++m_data->layers.top()->saveCounter; 295 m_data->p()->save(); 296 m_data->shadowStack.push(m_data->shadow); 297} 298 299void GraphicsContext::restorePlatformState() 300{ 301 if (!m_data->layers.isEmpty() && !m_data->layers.top()->alphaMask.isNull()) 302 if (!--m_data->layers.top()->saveCounter) 303 endTransparencyLayer(); 304 305 m_data->p()->restore(); 306 307 if (m_data->shadowStack.isEmpty()) 308 m_data->shadow = ContextShadow(); 309 else 310 m_data->shadow = m_data->shadowStack.pop(); 311} 312 313// Draws a filled rectangle with a stroked border. 314// This is only used to draw borders (real fill is done via fillRect), and 315// thus it must not cast any shadow. 316void GraphicsContext::drawRect(const IntRect& rect) 317{ 318 if (paintingDisabled()) 319 return; 320 321 QPainter* p = m_data->p(); 322 const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); 323 p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); 324 325 p->drawRect(rect); 326 327 p->setRenderHint(QPainter::Antialiasing, antiAlias); 328} 329 330// This is only used to draw borders. 331// Must not cast any shadow. 332void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) 333{ 334 if (paintingDisabled()) 335 return; 336 337 StrokeStyle style = strokeStyle(); 338 Color color = strokeColor(); 339 if (style == NoStroke) 340 return; 341 342 float width = strokeThickness(); 343 344 FloatPoint p1 = point1; 345 FloatPoint p2 = point2; 346 bool isVerticalLine = (p1.x() == p2.x()); 347 348 QPainter* p = m_data->p(); 349 const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); 350 p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); 351 adjustLineToPixelBoundaries(p1, p2, width, style); 352 353 int patWidth = 0; 354 switch (style) { 355 case NoStroke: 356 case SolidStroke: 357 break; 358 case DottedStroke: 359 patWidth = static_cast<int>(width); 360 break; 361 case DashedStroke: 362 patWidth = 3 * static_cast<int>(width); 363 break; 364 } 365 366 if (patWidth) { 367 p->save(); 368 369 // Do a rect fill of our endpoints. This ensures we always have the 370 // appearance of being a border. We then draw the actual dotted/dashed line. 371 if (isVerticalLine) { 372 p->fillRect(FloatRect(p1.x() - width / 2, p1.y() - width, width, width), QColor(color)); 373 p->fillRect(FloatRect(p2.x() - width / 2, p2.y(), width, width), QColor(color)); 374 } else { 375 p->fillRect(FloatRect(p1.x() - width, p1.y() - width / 2, width, width), QColor(color)); 376 p->fillRect(FloatRect(p2.x(), p2.y() - width / 2, width, width), QColor(color)); 377 } 378 379 // Example: 80 pixels with a width of 30 pixels. 380 // Remainder is 20. The maximum pixels of line we could paint 381 // will be 50 pixels. 382 int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*(int)width; 383 int remainder = distance % patWidth; 384 int coverage = distance - remainder; 385 int numSegments = coverage / patWidth; 386 387 float patternOffset = 0.0f; 388 // Special case 1px dotted borders for speed. 389 if (patWidth == 1) 390 patternOffset = 1.0f; 391 else { 392 bool evenNumberOfSegments = !(numSegments % 2); 393 if (remainder) 394 evenNumberOfSegments = !evenNumberOfSegments; 395 if (evenNumberOfSegments) { 396 if (remainder) { 397 patternOffset += patWidth - remainder; 398 patternOffset += remainder / 2; 399 } else 400 patternOffset = patWidth / 2; 401 } else { 402 if (remainder) 403 patternOffset = (patWidth - remainder) / 2; 404 } 405 } 406 407 QVector<qreal> dashes; 408 dashes << qreal(patWidth) / width << qreal(patWidth) / width; 409 410 QPen pen = p->pen(); 411 pen.setWidthF(width); 412 pen.setCapStyle(Qt::FlatCap); 413 pen.setDashPattern(dashes); 414 pen.setDashOffset(patternOffset / width); 415 p->setPen(pen); 416 } 417 418 p->drawLine(p1, p2); 419 420 if (patWidth) 421 p->restore(); 422 423 p->setRenderHint(QPainter::Antialiasing, antiAlias); 424} 425 426// This method is only used to draw the little circles used in lists. 427void GraphicsContext::drawEllipse(const IntRect& rect) 428{ 429 if (paintingDisabled()) 430 return; 431 432 m_data->p()->drawEllipse(rect); 433} 434 435void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias) 436{ 437 if (paintingDisabled()) 438 return; 439 440 if (npoints <= 1) 441 return; 442 443 QPolygonF polygon(npoints); 444 445 for (size_t i = 0; i < npoints; i++) 446 polygon[i] = points[i]; 447 448 QPainter* p = m_data->p(); 449 450 const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); 451 p->setRenderHint(QPainter::Antialiasing, shouldAntialias); 452 453 p->drawConvexPolygon(polygon); 454 455 p->setRenderHint(QPainter::Antialiasing, antiAlias); 456} 457 458void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased) 459{ 460 if (paintingDisabled()) 461 return; 462 463 if (numPoints <= 1) 464 return; 465 466 QPainterPath path(points[0]); 467 for (size_t i = 1; i < numPoints; ++i) 468 path.lineTo(points[i]); 469 path.setFillRule(Qt::WindingFill); 470 471 QPainter* p = m_data->p(); 472 473 bool painterWasAntialiased = p->testRenderHint(QPainter::Antialiasing); 474 475 if (painterWasAntialiased != antialiased) 476 p->setRenderHint(QPainter::Antialiasing, antialiased); 477 478 p->setClipPath(path, Qt::IntersectClip); 479 480 if (painterWasAntialiased != antialiased) 481 p->setRenderHint(QPainter::Antialiasing, painterWasAntialiased); 482} 483 484void GraphicsContext::fillPath(const Path& path) 485{ 486 if (paintingDisabled()) 487 return; 488 489 QPainter* p = m_data->p(); 490 QPainterPath platformPath = path.platformPath(); 491 platformPath.setFillRule(toQtFillRule(fillRule())); 492 493 if (hasShadow()) { 494 ContextShadow* shadow = contextShadow(); 495 if (shadow->mustUseContextShadow(this) || m_state.fillPattern || m_state.fillGradient) 496 { 497 QPainter* shadowPainter = shadow->beginShadowLayer(this, platformPath.controlPointRect()); 498 if (shadowPainter) { 499 if (m_state.fillPattern) { 500 AffineTransform affine; 501 shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255); 502 shadowPainter->fillPath(platformPath, QBrush(m_state.fillPattern->createPlatformPattern(affine))); 503 } else if (m_state.fillGradient) { 504 QBrush brush(*m_state.fillGradient->platformGradient()); 505 brush.setTransform(m_state.fillGradient->gradientSpaceTransform()); 506 shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255); 507 shadowPainter->fillPath(platformPath, brush); 508 } else 509 shadowPainter->fillPath(platformPath, QColor(shadow->m_color)); 510 shadow->endShadowLayer(this); 511 } 512 } else { 513 QPointF offset = shadow->offset(); 514 p->translate(offset); 515 p->fillPath(platformPath, QColor(shadow->m_color)); 516 p->translate(-offset); 517 } 518 } 519 if (m_state.fillPattern) { 520 AffineTransform affine; 521 p->fillPath(platformPath, QBrush(m_state.fillPattern->createPlatformPattern(affine))); 522 } else if (m_state.fillGradient) { 523 QBrush brush(*m_state.fillGradient->platformGradient()); 524 brush.setTransform(m_state.fillGradient->gradientSpaceTransform()); 525 p->fillPath(platformPath, brush); 526 } else 527 p->fillPath(platformPath, p->brush()); 528} 529 530void GraphicsContext::strokePath(const Path& path) 531{ 532 if (paintingDisabled()) 533 return; 534 535 QPainter* p = m_data->p(); 536 QPen pen(p->pen()); 537 QPainterPath platformPath = path.platformPath(); 538 platformPath.setFillRule(toQtFillRule(fillRule())); 539 540 if (hasShadow()) { 541 ContextShadow* shadow = contextShadow(); 542 if (shadow->mustUseContextShadow(this) || m_state.strokePattern || m_state.strokeGradient) 543 { 544 FloatRect boundingRect = platformPath.controlPointRect(); 545 boundingRect.inflate(pen.miterLimit() + pen.widthF()); 546 QPainter* shadowPainter = shadow->beginShadowLayer(this, boundingRect); 547 if (shadowPainter) { 548 shadowPainter->setOpacity(static_cast<qreal>(m_data->shadow.m_color.alpha()) / 255); 549 shadowPainter->strokePath(platformPath, pen); 550 shadow->endShadowLayer(this); 551 } 552 } else { 553 QPen shadowPen(pen); 554 shadowPen.setColor(m_data->shadow.m_color); 555 QPointF offset = shadow->offset(); 556 p->translate(offset); 557 p->strokePath(platformPath, shadowPen); 558 p->translate(-offset); 559 } 560 } 561 562 if (m_state.strokePattern) { 563 AffineTransform affine; 564 pen.setBrush(QBrush(m_state.strokePattern->createPlatformPattern(affine))); 565 p->setPen(pen); 566 p->strokePath(platformPath, pen); 567 } else if (m_state.strokeGradient) { 568 QBrush brush(*m_state.strokeGradient->platformGradient()); 569 brush.setTransform(m_state.strokeGradient->gradientSpaceTransform()); 570 pen.setBrush(brush); 571 p->setPen(pen); 572 p->strokePath(platformPath, pen); 573 } else 574 p->strokePath(platformPath, pen); 575} 576 577static inline void drawRepeatPattern(QPainter* p, QPixmap* image, const FloatRect& rect, const bool repeatX, const bool repeatY) 578{ 579 // Patterns must be painted so that the top left of the first image is anchored at 580 // the origin of the coordinate space 581 if (image) { 582 int w = image->width(); 583 int h = image->height(); 584 int startX, startY; 585 QRect r(static_cast<int>(rect.x()), static_cast<int>(rect.y()), static_cast<int>(rect.width()), static_cast<int>(rect.height())); 586 587 // startX, startY is the coordinate of the first image we need to put on the left-top of the rect 588 if (repeatX && repeatY) { 589 // repeat 590 // startX, startY is at the left top side of the left-top of the rect 591 startX = r.x() >=0 ? r.x() - (r.x() % w) : r.x() - (w - qAbs(r.x()) % w); 592 startY = r.y() >=0 ? r.y() - (r.y() % h) : r.y() - (h - qAbs(r.y()) % h); 593 } else { 594 if (!repeatX && !repeatY) { 595 // no-repeat 596 // only draw the image once at orgin once, check if need to draw 597 QRect imageRect(0, 0, w, h); 598 if (imageRect.intersects(r)) { 599 startX = 0; 600 startY = 0; 601 } else 602 return; 603 } else if (repeatX && !repeatY) { 604 // repeat-x 605 // startY is fixed, but startX change based on the left-top of the rect 606 QRect imageRect(r.x(), 0, r.width(), h); 607 if (imageRect.intersects(r)) { 608 startX = r.x() >=0 ? r.x() - (r.x() % w) : r.x() - (w - qAbs(r.x()) % w); 609 startY = 0; 610 } else 611 return; 612 } else { 613 // repeat-y 614 // startX is fixed, but startY change based on the left-top of the rect 615 QRect imageRect(0, r.y(), w, r.height()); 616 if (imageRect.intersects(r)) { 617 startX = 0; 618 startY = r.y() >=0 ? r.y() - (r.y() % h) : r.y() - (h - qAbs(r.y()) % h); 619 } else 620 return; 621 } 622 } 623 624 int x = startX; 625 int y = startY; 626 do { 627 // repeat Y 628 do { 629 // repeat X 630 QRect imageRect(x, y, w, h); 631 QRect intersectRect = imageRect.intersected(r); 632 QPoint destStart(intersectRect.x(), intersectRect.y()); 633 QRect sourceRect(intersectRect.x() - imageRect.x(), intersectRect.y() - imageRect.y(), intersectRect.width(), intersectRect.height()); 634 635 p->drawPixmap(destStart, *image, sourceRect); 636 x += w; 637 } while (repeatX && x < r.x() + r.width()); 638 x = startX; 639 y += h; 640 } while (repeatY && y < r.y() + r.height()); 641 } 642} 643 644void GraphicsContext::fillRect(const FloatRect& rect) 645{ 646 if (paintingDisabled()) 647 return; 648 649 QPainter* p = m_data->p(); 650 QRectF normalizedRect = rect.normalized(); 651 ContextShadow* shadow = contextShadow(); 652 653 if (m_state.fillPattern) { 654 AffineTransform affine; 655 QBrush brush(m_state.fillPattern->createPlatformPattern(affine)); 656 QPixmap* image = m_state.fillPattern->tileImage()->nativeImageForCurrentFrame(); 657 QPainter* shadowPainter = hasShadow() ? shadow->beginShadowLayer(this, normalizedRect) : 0; 658 if (shadowPainter) { 659 drawRepeatPattern(shadowPainter, image, normalizedRect, m_state.fillPattern->repeatX(), m_state.fillPattern->repeatY()); 660 shadowPainter->setCompositionMode(QPainter::CompositionMode_SourceIn); 661 shadowPainter->fillRect(normalizedRect, shadow->m_color); 662 shadow->endShadowLayer(this); 663 } 664 drawRepeatPattern(p, image, normalizedRect, m_state.fillPattern->repeatX(), m_state.fillPattern->repeatY()); 665 } else if (m_state.fillGradient) { 666 QBrush brush(*m_state.fillGradient->platformGradient()); 667 brush.setTransform(m_state.fillGradient->gradientSpaceTransform()); 668 QPainter* shadowPainter = hasShadow() ? shadow->beginShadowLayer(this, normalizedRect) : 0; 669 if (shadowPainter) { 670 shadowPainter->fillRect(normalizedRect, brush); 671 shadowPainter->setCompositionMode(QPainter::CompositionMode_SourceIn); 672 shadowPainter->fillRect(normalizedRect, shadow->m_color); 673 shadow->endShadowLayer(this); 674 } 675 p->fillRect(normalizedRect, brush); 676 } else { 677 if (hasShadow()) { 678 if (shadow->mustUseContextShadow(this)) { 679 QPainter* shadowPainter = shadow->beginShadowLayer(this, normalizedRect); 680 if (shadowPainter) { 681 shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255); 682 shadowPainter->fillRect(normalizedRect, p->brush()); 683 shadow->endShadowLayer(this); 684 } 685 } else { 686 // Solid rectangle fill with no blur shadow or transformations applied can be done 687 // faster without using the shadow layer at all. 688 QColor shadowColor = shadow->m_color; 689 shadowColor.setAlphaF(shadowColor.alphaF() * p->brush().color().alphaF()); 690 p->fillRect(normalizedRect.translated(shadow->offset()), shadowColor); 691 } 692 } 693 694 p->fillRect(normalizedRect, p->brush()); 695 } 696} 697 698 699void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) 700{ 701 if (paintingDisabled() || !color.isValid()) 702 return; 703 704 m_data->solidColor.setColor(color); 705 QPainter* p = m_data->p(); 706 QRectF normalizedRect = rect.normalized(); 707 708 if (hasShadow()) { 709 ContextShadow* shadow = contextShadow(); 710 if (shadow->mustUseContextShadow(this)) { 711 QPainter* shadowPainter = shadow->beginShadowLayer(this, normalizedRect); 712 if (shadowPainter) { 713 shadowPainter->setCompositionMode(QPainter::CompositionMode_Source); 714 shadowPainter->fillRect(normalizedRect, shadow->m_color); 715 shadow->endShadowLayer(this); 716 } 717 } else 718 p->fillRect(normalizedRect.translated(shadow->offset()), shadow->m_color); 719 } 720 721 p->fillRect(normalizedRect, m_data->solidColor); 722} 723 724void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) 725{ 726 if (paintingDisabled() || !color.isValid()) 727 return; 728 729 Path path; 730 path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight); 731 QPainter* p = m_data->p(); 732 if (hasShadow()) { 733 ContextShadow* shadow = contextShadow(); 734 if (shadow->mustUseContextShadow(this)) { 735 QPainter* shadowPainter = shadow->beginShadowLayer(this, rect); 736 if (shadowPainter) { 737 shadowPainter->setCompositionMode(QPainter::CompositionMode_Source); 738 shadowPainter->fillPath(path.platformPath(), QColor(m_data->shadow.m_color)); 739 shadow->endShadowLayer(this); 740 } 741 } else { 742 p->translate(m_data->shadow.offset()); 743 p->fillPath(path.platformPath(), QColor(m_data->shadow.m_color)); 744 p->translate(-m_data->shadow.offset()); 745 } 746 } 747 p->fillPath(path.platformPath(), QColor(color)); 748} 749 750bool GraphicsContext::inTransparencyLayer() const 751{ 752 return m_data->layerCount; 753} 754 755ContextShadow* GraphicsContext::contextShadow() 756{ 757 return &m_data->shadow; 758} 759 760void GraphicsContext::clip(const FloatRect& rect) 761{ 762 if (paintingDisabled()) 763 return; 764 765 m_data->p()->setClipRect(rect, Qt::IntersectClip); 766} 767 768void GraphicsContext::clipPath(const Path& path, WindRule clipRule) 769{ 770 if (paintingDisabled()) 771 return; 772 773 QPainter* p = m_data->p(); 774 QPainterPath platformPath = path.platformPath(); 775 platformPath.setFillRule(clipRule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill); 776 p->setClipPath(platformPath, Qt::IntersectClip); 777} 778 779void drawFocusRingForPath(QPainter* p, const QPainterPath& path, int width, const Color& color, bool antiAliasing) 780{ 781 const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); 782 p->setRenderHint(QPainter::Antialiasing, antiAliasing); 783 784 const QPen oldPen = p->pen(); 785 const QBrush oldBrush = p->brush(); 786 787 QPen nPen = p->pen(); 788 nPen.setColor(color); 789 nPen.setWidth(width); 790 p->setBrush(Qt::NoBrush); 791 nPen.setStyle(Qt::SolidLine); 792 793 p->strokePath(path, nPen); 794 p->setBrush(oldBrush); 795 p->setPen(oldPen); 796 797 p->setRenderHint(QPainter::Antialiasing, antiAlias); 798} 799 800void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color) 801{ 802 // FIXME: Use 'offset' for something? http://webkit.org/b/49909 803 804 if (paintingDisabled() || !color.isValid()) 805 return; 806 807 drawFocusRingForPath(m_data->p(), path.platformPath(), width, color, m_data->antiAliasingForRectsAndLines); 808} 809 810/** 811 * Focus ring handling for form controls is not handled here. Qt style in 812 * RenderTheme handles drawing focus on widgets which 813 * need it. It is still handled here for links. 814 */ 815void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color) 816{ 817 if (paintingDisabled() || !color.isValid()) 818 return; 819 820 unsigned rectCount = rects.size(); 821 822 if (!rects.size()) 823 return; 824 825 int radius = (width - 1) / 2; 826 QPainterPath path; 827 for (unsigned i = 0; i < rectCount; ++i) { 828 QRect rect = QRect((rects[i])).adjusted(-offset - radius, -offset - radius, offset + radius, offset + radius); 829 // This is not the most efficient way to add a rect to a path, but if we don't create the tmpPath, 830 // we will end up with ugly lines in between rows of text on anchors with multiple lines. 831 QPainterPath tmpPath; 832 tmpPath.addRoundedRect(rect, radius, radius); 833 path = path.united(tmpPath); 834 } 835 836 drawFocusRingForPath(m_data->p(), path, width, color, m_data->antiAliasingForRectsAndLines); 837} 838 839void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool) 840{ 841 if (paintingDisabled()) 842 return; 843 844 IntPoint startPoint = origin; 845 IntPoint endPoint = origin + IntSize(width, 0); 846 847 // If paintengine type is X11 to avoid artifacts 848 // like bug https://bugs.webkit.org/show_bug.cgi?id=42248 849#if defined(Q_WS_X11) 850 QPainter* p = m_data->p(); 851 if (p->paintEngine()->type() == QPaintEngine::X11) { 852 // If stroke thickness is odd we need decrease Y coordinate by 1 pixel, 853 // because inside method adjustLineToPixelBoundaries(...), which 854 // called from drawLine(...), Y coordinate will be increased by 0.5f 855 // and then inside Qt painting engine will be rounded to next greater 856 // integer value. 857 float strokeWidth = strokeThickness(); 858 if (static_cast<int>(strokeWidth) % 2) { 859 startPoint.setY(startPoint.y() - 1); 860 endPoint.setY(endPoint.y() - 1); 861 } 862 } 863#endif // defined(Q_WS_X11) 864 865 drawLine(startPoint, endPoint); 866} 867 868void GraphicsContext::drawLineForTextChecking(const IntPoint&, int, TextCheckingLineStyle) 869{ 870 if (paintingDisabled()) 871 return; 872 873 notImplemented(); 874} 875 876FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) 877{ 878 // It is not enough just to round to pixels in device space. The rotation part of the 879 // affine transform matrix to device space can mess with this conversion if we have a 880 // rotating image like the hands of the world clock widget. We just need the scale, so 881 // we get the affine transform matrix and extract the scale. 882 QPainter* painter = platformContext(); 883 QTransform deviceTransform = painter->deviceTransform(); 884 if (deviceTransform.isIdentity()) 885 return frect; 886 887 qreal deviceScaleX = sqrtf(deviceTransform.m11() * deviceTransform.m11() + deviceTransform.m12() * deviceTransform.m12()); 888 qreal deviceScaleY = sqrtf(deviceTransform.m21() * deviceTransform.m21() + deviceTransform.m22() * deviceTransform.m22()); 889 890 QPoint deviceOrigin(frect.x() * deviceScaleX, frect.y() * deviceScaleY); 891 QPoint deviceLowerRight(frect.right() * deviceScaleX, frect.bottom() * deviceScaleY); 892 893 // Don't let the height or width round to 0 unless either was originally 0 894 if (deviceOrigin.y() == deviceLowerRight.y() && frect.height()) 895 deviceLowerRight.setY(deviceLowerRight.y() + 1); 896 if (deviceOrigin.x() == deviceLowerRight.x() && frect.width()) 897 deviceLowerRight.setX(deviceLowerRight.x() + 1); 898 899 FloatPoint roundedOrigin = FloatPoint(deviceOrigin.x() / deviceScaleX, deviceOrigin.y() / deviceScaleY); 900 FloatPoint roundedLowerRight = FloatPoint(deviceLowerRight.x() / deviceScaleX, deviceLowerRight.y() / deviceScaleY); 901 return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin); 902} 903 904void GraphicsContext::setPlatformShadow(const FloatSize& size, float blur, const Color& color, ColorSpace) 905{ 906 // Qt doesn't support shadows natively, they are drawn manually in the draw* 907 // functions 908 909 if (m_state.shadowsIgnoreTransforms) { 910 // Meaning that this graphics context is associated with a CanvasRenderingContext 911 // We flip the height since CG and HTML5 Canvas have opposite Y axis 912 m_state.shadowOffset = FloatSize(size.width(), -size.height()); 913 m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), -size.height())); 914 } else 915 m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), size.height())); 916 917 m_data->shadow.setShadowsIgnoreTransforms(m_state.shadowsIgnoreTransforms); 918} 919 920void GraphicsContext::clearPlatformShadow() 921{ 922 m_data->shadow.clear(); 923} 924 925void GraphicsContext::pushTransparencyLayerInternal(const QRect &rect, qreal opacity, QPixmap& alphaMask) 926{ 927 QPainter* p = m_data->p(); 928 m_data->layers.push(new TransparencyLayer(p, p->transform().mapRect(rect), 1.0, alphaMask)); 929} 930 931void GraphicsContext::beginTransparencyLayer(float opacity) 932{ 933 if (paintingDisabled()) 934 return; 935 936 int x, y, w, h; 937 x = y = 0; 938 QPainter* p = m_data->p(); 939 const QPaintDevice* device = p->device(); 940 w = device->width(); 941 h = device->height(); 942 943 QRectF clip = m_data->clipBoundingRect(); 944 QRectF deviceClip = p->transform().mapRect(clip); 945 x = int(qBound(qreal(0), deviceClip.x(), (qreal)w)); 946 y = int(qBound(qreal(0), deviceClip.y(), (qreal)h)); 947 w = int(qBound(qreal(0), deviceClip.width(), (qreal)w) + 2); 948 h = int(qBound(qreal(0), deviceClip.height(), (qreal)h) + 2); 949 950 QPixmap emptyAlphaMask; 951 m_data->layers.push(new TransparencyLayer(p, QRect(x, y, w, h), opacity, emptyAlphaMask)); 952 ++m_data->layerCount; 953} 954 955void GraphicsContext::endTransparencyLayer() 956{ 957 if (paintingDisabled()) 958 return; 959 960 TransparencyLayer* layer = m_data->layers.pop(); 961 if (!layer->alphaMask.isNull()) { 962 layer->painter.resetTransform(); 963 layer->painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); 964 layer->painter.drawPixmap(QPoint(), layer->alphaMask); 965 } else 966 --m_data->layerCount; // see the comment for layerCount 967 layer->painter.end(); 968 969 QPainter* p = m_data->p(); 970 p->save(); 971 p->resetTransform(); 972 p->setOpacity(layer->opacity); 973 p->drawPixmap(layer->offset, layer->pixmap); 974 p->restore(); 975 976 delete layer; 977} 978 979void GraphicsContext::clearRect(const FloatRect& rect) 980{ 981 if (paintingDisabled()) 982 return; 983 984 QPainter* p = m_data->p(); 985 QPainter::CompositionMode currentCompositionMode = p->compositionMode(); 986 if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) 987 p->setCompositionMode(QPainter::CompositionMode_Source); 988 p->fillRect(rect, Qt::transparent); 989 if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) 990 p->setCompositionMode(currentCompositionMode); 991} 992 993void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) 994{ 995 if (paintingDisabled()) 996 return; 997 998 Path path; 999 path.addRect(rect); 1000 1001 float previousStrokeThickness = strokeThickness(); 1002 1003 if (lineWidth != previousStrokeThickness) 1004 setStrokeThickness(lineWidth); 1005 1006 strokePath(path); 1007 1008 if (lineWidth != previousStrokeThickness) 1009 setStrokeThickness(previousStrokeThickness); 1010} 1011 1012void GraphicsContext::setLineCap(LineCap lc) 1013{ 1014 if (paintingDisabled()) 1015 return; 1016 1017 QPainter* p = m_data->p(); 1018 QPen nPen = p->pen(); 1019 nPen.setCapStyle(toQtLineCap(lc)); 1020 p->setPen(nPen); 1021} 1022 1023void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) 1024{ 1025 QPainter* p = m_data->p(); 1026 QPen pen = p->pen(); 1027 unsigned dashLength = dashes.size(); 1028 if (dashLength) { 1029 QVector<qreal> pattern; 1030 unsigned count = dashLength; 1031 if (dashLength % 2) 1032 count *= 2; 1033 1034 float penWidth = narrowPrecisionToFloat(double(pen.widthF())); 1035 for (unsigned i = 0; i < count; i++) 1036 pattern.append(dashes[i % dashLength] / penWidth); 1037 1038 pen.setDashPattern(pattern); 1039 pen.setDashOffset(dashOffset / penWidth); 1040 } else 1041 pen.setStyle(Qt::SolidLine); 1042 p->setPen(pen); 1043} 1044 1045void GraphicsContext::setLineJoin(LineJoin lj) 1046{ 1047 if (paintingDisabled()) 1048 return; 1049 1050 QPainter* p = m_data->p(); 1051 QPen nPen = p->pen(); 1052 nPen.setJoinStyle(toQtLineJoin(lj)); 1053 p->setPen(nPen); 1054} 1055 1056void GraphicsContext::setMiterLimit(float limit) 1057{ 1058 if (paintingDisabled()) 1059 return; 1060 1061 QPainter* p = m_data->p(); 1062 QPen nPen = p->pen(); 1063 nPen.setMiterLimit(limit); 1064 p->setPen(nPen); 1065} 1066 1067void GraphicsContext::setAlpha(float opacity) 1068{ 1069 if (paintingDisabled()) 1070 return; 1071 QPainter* p = m_data->p(); 1072 p->setOpacity(opacity); 1073} 1074 1075void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op) 1076{ 1077 if (paintingDisabled()) 1078 return; 1079 1080 QPainter* painter = m_data->p(); 1081 1082 if (!painter->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) 1083 return; 1084 1085 painter->setCompositionMode(toQtCompositionMode(op)); 1086} 1087 1088void GraphicsContext::clip(const Path& path) 1089{ 1090 if (paintingDisabled()) 1091 return; 1092 1093 QPainterPath clipPath = path.platformPath(); 1094 clipPath.setFillRule(Qt::WindingFill); 1095 m_data->p()->setClipPath(clipPath, Qt::IntersectClip); 1096} 1097 1098void GraphicsContext::canvasClip(const Path& path) 1099{ 1100 clip(path); 1101} 1102 1103void GraphicsContext::clipOut(const Path& path) 1104{ 1105 if (paintingDisabled()) 1106 return; 1107 1108 QPainter* p = m_data->p(); 1109 QPainterPath clippedOut = path.platformPath(); 1110 QPainterPath newClip; 1111 newClip.setFillRule(Qt::OddEvenFill); 1112 if (p->hasClipping()) { 1113 newClip.addRect(m_data->clipBoundingRect()); 1114 newClip.addPath(clippedOut); 1115 p->setClipPath(newClip, Qt::IntersectClip); 1116 } else { 1117 QRect windowRect = p->transform().inverted().mapRect(p->window()); 1118 newClip.addRect(windowRect); 1119 newClip.addPath(clippedOut.intersected(newClip)); 1120 p->setClipPath(newClip); 1121 } 1122} 1123 1124void GraphicsContext::translate(float x, float y) 1125{ 1126 if (paintingDisabled()) 1127 return; 1128 1129 m_data->p()->translate(x, y); 1130} 1131 1132void GraphicsContext::rotate(float radians) 1133{ 1134 if (paintingDisabled()) 1135 return; 1136 1137 m_data->p()->rotate(180 / M_PI*radians); 1138} 1139 1140void GraphicsContext::scale(const FloatSize& s) 1141{ 1142 if (paintingDisabled()) 1143 return; 1144 1145 m_data->p()->scale(s.width(), s.height()); 1146} 1147 1148void GraphicsContext::clipOut(const IntRect& rect) 1149{ 1150 if (paintingDisabled()) 1151 return; 1152 1153 QPainter* p = m_data->p(); 1154 QPainterPath newClip; 1155 newClip.setFillRule(Qt::OddEvenFill); 1156 if (p->hasClipping()) { 1157 newClip.addRect(m_data->clipBoundingRect()); 1158 newClip.addRect(QRect(rect)); 1159 p->setClipPath(newClip, Qt::IntersectClip); 1160 } else { 1161 QRect clipOutRect(rect); 1162 QRect window = p->transform().inverted().mapRect(p->window()); 1163 clipOutRect &= window; 1164 newClip.addRect(window); 1165 newClip.addRect(clipOutRect); 1166 p->setClipPath(newClip); 1167 } 1168} 1169 1170void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, 1171 int thickness) 1172{ 1173 if (paintingDisabled()) 1174 return; 1175 1176 clip(rect); 1177 QPainterPath path; 1178 1179 // Add outer ellipse 1180 path.addEllipse(QRectF(rect.x(), rect.y(), rect.width(), rect.height())); 1181 1182 // Add inner ellipse. 1183 path.addEllipse(QRectF(rect.x() + thickness, rect.y() + thickness, 1184 rect.width() - (thickness * 2), rect.height() - (thickness * 2))); 1185 1186 path.setFillRule(Qt::OddEvenFill); 1187 1188 QPainter* p = m_data->p(); 1189 1190 const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); 1191 p->setRenderHint(QPainter::Antialiasing, true); 1192 p->setClipPath(path, Qt::IntersectClip); 1193 p->setRenderHint(QPainter::Antialiasing, antiAlias); 1194} 1195 1196void GraphicsContext::concatCTM(const AffineTransform& transform) 1197{ 1198 if (paintingDisabled()) 1199 return; 1200 1201 m_data->p()->setWorldTransform(transform, true); 1202} 1203 1204void GraphicsContext::setURLForRect(const KURL&, const IntRect&) 1205{ 1206 notImplemented(); 1207} 1208 1209void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace) 1210{ 1211 if (paintingDisabled() || !color.isValid()) 1212 return; 1213 1214 QPainter* p = m_data->p(); 1215 QPen newPen(p->pen()); 1216 m_data->solidColor.setColor(color); 1217 newPen.setBrush(m_data->solidColor); 1218 p->setPen(newPen); 1219} 1220 1221void GraphicsContext::setPlatformStrokeStyle(StrokeStyle strokeStyle) 1222{ 1223 if (paintingDisabled()) 1224 return; 1225 QPainter* p = m_data->p(); 1226 QPen newPen(p->pen()); 1227 newPen.setStyle(toQPenStyle(strokeStyle)); 1228 p->setPen(newPen); 1229} 1230 1231void GraphicsContext::setPlatformStrokeThickness(float thickness) 1232{ 1233 if (paintingDisabled()) 1234 return; 1235 QPainter* p = m_data->p(); 1236 QPen newPen(p->pen()); 1237 newPen.setWidthF(thickness); 1238 p->setPen(newPen); 1239} 1240 1241void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) 1242{ 1243 if (paintingDisabled() || !color.isValid()) 1244 return; 1245 1246 m_data->solidColor.setColor(color); 1247 m_data->p()->setBrush(m_data->solidColor); 1248} 1249 1250void GraphicsContext::setPlatformShouldAntialias(bool enable) 1251{ 1252 if (paintingDisabled()) 1253 return; 1254 m_data->p()->setRenderHint(QPainter::Antialiasing, enable); 1255} 1256 1257#ifdef Q_WS_WIN 1258 1259HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) 1260{ 1261 // painting through native HDC is only supported for plugin, where mayCreateBitmap is always true 1262 Q_ASSERT(mayCreateBitmap); 1263 1264 if (dstRect.isEmpty()) 1265 return 0; 1266 1267 // Create a bitmap DC in which to draw. 1268 BITMAPINFO bitmapInfo; 1269 bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 1270 bitmapInfo.bmiHeader.biWidth = dstRect.width(); 1271 bitmapInfo.bmiHeader.biHeight = dstRect.height(); 1272 bitmapInfo.bmiHeader.biPlanes = 1; 1273 bitmapInfo.bmiHeader.biBitCount = 32; 1274 bitmapInfo.bmiHeader.biCompression = BI_RGB; 1275 bitmapInfo.bmiHeader.biSizeImage = 0; 1276 bitmapInfo.bmiHeader.biXPelsPerMeter = 0; 1277 bitmapInfo.bmiHeader.biYPelsPerMeter = 0; 1278 bitmapInfo.bmiHeader.biClrUsed = 0; 1279 bitmapInfo.bmiHeader.biClrImportant = 0; 1280 1281 void* pixels = 0; 1282 HBITMAP bitmap = ::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0); 1283 if (!bitmap) 1284 return 0; 1285 1286 HDC displayDC = ::GetDC(0); 1287 HDC bitmapDC = ::CreateCompatibleDC(displayDC); 1288 ::ReleaseDC(0, displayDC); 1289 1290 ::SelectObject(bitmapDC, bitmap); 1291 1292 // Fill our buffer with clear if we're going to alpha blend. 1293 if (supportAlphaBlend) { 1294 BITMAP bmpInfo; 1295 GetObject(bitmap, sizeof(bmpInfo), &bmpInfo); 1296 int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; 1297 memset(bmpInfo.bmBits, 0, bufferSize); 1298 } 1299 1300#if !OS(WINCE) 1301 // Make sure we can do world transforms. 1302 SetGraphicsMode(bitmapDC, GM_ADVANCED); 1303 1304 // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap. 1305 XFORM xform; 1306 xform.eM11 = 1.0f; 1307 xform.eM12 = 0.0f; 1308 xform.eM21 = 0.0f; 1309 xform.eM22 = 1.0f; 1310 xform.eDx = -dstRect.x(); 1311 xform.eDy = -dstRect.y(); 1312 ::SetWorldTransform(bitmapDC, &xform); 1313#endif 1314 1315 return bitmapDC; 1316} 1317 1318void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) 1319{ 1320 // painting through native HDC is only supported for plugin, where mayCreateBitmap is always true 1321 Q_ASSERT(mayCreateBitmap); 1322 1323 if (hdc) { 1324 1325 if (!dstRect.isEmpty()) { 1326 1327 HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); 1328 BITMAP info; 1329 GetObject(bitmap, sizeof(info), &info); 1330 ASSERT(info.bmBitsPixel == 32); 1331 1332 QPixmap pixmap = QPixmap::fromWinHBITMAP(bitmap, supportAlphaBlend ? QPixmap::PremultipliedAlpha : QPixmap::NoAlpha); 1333 m_data->p()->drawPixmap(dstRect, pixmap); 1334 1335 ::DeleteObject(bitmap); 1336 } 1337 1338 ::DeleteDC(hdc); 1339 } 1340} 1341#endif 1342 1343void GraphicsContext::setImageInterpolationQuality(InterpolationQuality quality) 1344{ 1345 m_data->imageInterpolationQuality = quality; 1346 1347 switch (quality) { 1348 case InterpolationNone: 1349 case InterpolationLow: 1350 // use nearest-neigbor 1351 m_data->p()->setRenderHint(QPainter::SmoothPixmapTransform, false); 1352 break; 1353 1354 case InterpolationMedium: 1355 case InterpolationHigh: 1356 // use the filter 1357 m_data->p()->setRenderHint(QPainter::SmoothPixmapTransform, true); 1358 break; 1359 1360 case InterpolationDefault: 1361 default: 1362 m_data->p()->setRenderHint(QPainter::SmoothPixmapTransform, m_data->initialSmoothPixmapTransformHint); 1363 break; 1364 }; 1365} 1366 1367InterpolationQuality GraphicsContext::imageInterpolationQuality() const 1368{ 1369 return m_data->imageInterpolationQuality; 1370} 1371 1372void GraphicsContext::takeOwnershipOfPlatformContext() 1373{ 1374 m_data->takeOwnershipOfPlatformContext(); 1375} 1376 1377} 1378 1379// vim: ts=4 sw=4 et 1380