/src/3rdparty/webkit/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp

https://bitbucket.org/ultra_iter/qt-vtl · C++ · 1407 lines · 1078 code · 223 blank · 106 comment · 179 complexity · 944481a51236f713631ad4011eb7ce09 MD5 · raw file

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