/src/gui/painting/qblendfunctions_p.h

https://bitbucket.org/ultra_iter/qt-vtl · C Header · 497 lines · 354 code · 68 blank · 75 comment · 56 complexity · 141ea65eb22b6381f37abfadba16afb9 MD5 · raw file

  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
  4. ** All rights reserved.
  5. ** Contact: Nokia Corporation (qt-info@nokia.com)
  6. **
  7. ** This file is part of the QtGui module of the Qt Toolkit.
  8. **
  9. ** $QT_BEGIN_LICENSE:LGPL$
  10. ** GNU Lesser General Public License Usage
  11. ** This file may be used under the terms of the GNU Lesser General Public
  12. ** License version 2.1 as published by the Free Software Foundation and
  13. ** appearing in the file LICENSE.LGPL included in the packaging of this
  14. ** file. Please review the following information to ensure the GNU Lesser
  15. ** General Public License version 2.1 requirements will be met:
  16. ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  17. **
  18. ** In addition, as a special exception, Nokia gives you certain additional
  19. ** rights. These rights are described in the Nokia Qt LGPL Exception
  20. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  21. **
  22. ** GNU General Public License Usage
  23. ** Alternatively, this file may be used under the terms of the GNU General
  24. ** Public License version 3.0 as published by the Free Software Foundation
  25. ** and appearing in the file LICENSE.GPL included in the packaging of this
  26. ** file. Please review the following information to ensure the GNU General
  27. ** Public License version 3.0 requirements will be met:
  28. ** http://www.gnu.org/copyleft/gpl.html.
  29. **
  30. ** Other Usage
  31. ** Alternatively, this file may be used in accordance with the terms and
  32. ** conditions contained in a signed written agreement between you and Nokia.
  33. **
  34. **
  35. **
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. #ifndef QBLENDFUNCTIONS_P_H
  42. #define QBLENDFUNCTIONS_P_H
  43. #include <qmath.h>
  44. #include "qdrawhelper_p.h"
  45. QT_BEGIN_NAMESPACE
  46. //
  47. // W A R N I N G
  48. // -------------
  49. //
  50. // This file is not part of the Qt API. It exists purely as an
  51. // implementation detail. This header file may change from version to
  52. // version without notice, or even be removed.
  53. //
  54. // We mean it.
  55. //
  56. template <typename SRC, typename T>
  57. void qt_scale_image_16bit(uchar *destPixels, int dbpl,
  58. const uchar *srcPixels, int sbpl,
  59. const QRectF &targetRect,
  60. const QRectF &srcRect,
  61. const QRect &clip,
  62. T blender)
  63. {
  64. qreal sx = targetRect.width() / (qreal) srcRect.width();
  65. qreal sy = targetRect.height() / (qreal) srcRect.height();
  66. int ix = 0x00010000 / sx;
  67. int iy = 0x00010000 / sy;
  68. // qDebug() << "scale:" << endl
  69. // << " - target" << targetRect << endl
  70. // << " - source" << srcRect << endl
  71. // << " - clip" << clip << endl
  72. // << " - sx=" << sx << " sy=" << sy << " ix=" << ix << " iy=" << iy;
  73. int cx1 = clip.x();
  74. int cx2 = clip.x() + clip.width();
  75. int cy1 = clip.top();
  76. int cy2 = clip.y() + clip.height();
  77. int tx1 = qRound(targetRect.left());
  78. int tx2 = qRound(targetRect.right());
  79. int ty1 = qRound(targetRect.top());
  80. int ty2 = qRound(targetRect.bottom());
  81. if (tx2 < tx1)
  82. qSwap(tx2, tx1);
  83. if (ty2 < ty1)
  84. qSwap(ty2, ty1);
  85. if (tx1 < cx1)
  86. tx1 = cx1;
  87. if (tx2 >= cx2)
  88. tx2 = cx2;
  89. if (tx1 >= tx2)
  90. return;
  91. if (ty1 < cy1)
  92. ty1 = cy1;
  93. if (ty2 >= cy2)
  94. ty2 = cy2;
  95. if (ty1 >= ty2)
  96. return;
  97. int h = ty2 - ty1;
  98. int w = tx2 - tx1;
  99. quint32 basex;
  100. quint32 srcy;
  101. if (sx < 0) {
  102. int dstx = qFloor((tx1 + qreal(0.5) - targetRect.right()) * ix) + 1;
  103. basex = quint32(srcRect.right() * 65536) + dstx;
  104. } else {
  105. int dstx = qCeil((tx1 + qreal(0.5) - targetRect.left()) * ix) - 1;
  106. basex = quint32(srcRect.left() * 65536) + dstx;
  107. }
  108. if (sy < 0) {
  109. int dsty = qFloor((ty1 + qreal(0.5) - targetRect.bottom()) * iy) + 1;
  110. srcy = quint32(srcRect.bottom() * 65536) + dsty;
  111. } else {
  112. int dsty = qCeil((ty1 + qreal(0.5) - targetRect.top()) * iy) - 1;
  113. srcy = quint32(srcRect.top() * 65536) + dsty;
  114. }
  115. quint16 *dst = ((quint16 *) (destPixels + ty1 * dbpl)) + tx1;
  116. while (h--) {
  117. const SRC *src = (const SRC *) (srcPixels + (srcy >> 16) * sbpl);
  118. int srcx = basex;
  119. int x = 0;
  120. for (; x<w-7; x+=8) {
  121. blender.write(&dst[x], src[srcx >> 16]); srcx += ix;
  122. blender.write(&dst[x+1], src[srcx >> 16]); srcx += ix;
  123. blender.write(&dst[x+2], src[srcx >> 16]); srcx += ix;
  124. blender.write(&dst[x+3], src[srcx >> 16]); srcx += ix;
  125. blender.write(&dst[x+4], src[srcx >> 16]); srcx += ix;
  126. blender.write(&dst[x+5], src[srcx >> 16]); srcx += ix;
  127. blender.write(&dst[x+6], src[srcx >> 16]); srcx += ix;
  128. blender.write(&dst[x+7], src[srcx >> 16]); srcx += ix;
  129. }
  130. for (; x<w; ++x) {
  131. blender.write(&dst[x], src[srcx >> 16]);
  132. srcx += ix;
  133. }
  134. blender.flush(&dst[x]);
  135. dst = (quint16 *)(((uchar *) dst) + dbpl);
  136. srcy += iy;
  137. }
  138. }
  139. template <typename T> void qt_scale_image_32bit(uchar *destPixels, int dbpl,
  140. const uchar *srcPixels, int sbpl,
  141. const QRectF &targetRect,
  142. const QRectF &srcRect,
  143. const QRect &clip,
  144. T blender)
  145. {
  146. qreal sx = targetRect.width() / (qreal) srcRect.width();
  147. qreal sy = targetRect.height() / (qreal) srcRect.height();
  148. int ix = 0x00010000 / sx;
  149. int iy = 0x00010000 / sy;
  150. // qDebug() << "scale:" << endl
  151. // << " - target" << targetRect << endl
  152. // << " - source" << srcRect << endl
  153. // << " - clip" << clip << endl
  154. // << " - sx=" << sx << " sy=" << sy << " ix=" << ix << " iy=" << iy;
  155. int cx1 = clip.x();
  156. int cx2 = clip.x() + clip.width();
  157. int cy1 = clip.top();
  158. int cy2 = clip.y() + clip.height();
  159. int tx1 = qRound(targetRect.left());
  160. int tx2 = qRound(targetRect.right());
  161. int ty1 = qRound(targetRect.top());
  162. int ty2 = qRound(targetRect.bottom());
  163. if (tx2 < tx1)
  164. qSwap(tx2, tx1);
  165. if (ty2 < ty1)
  166. qSwap(ty2, ty1);
  167. if (tx1 < cx1)
  168. tx1 = cx1;
  169. if (tx2 >= cx2)
  170. tx2 = cx2;
  171. if (tx1 >= tx2)
  172. return;
  173. if (ty1 < cy1)
  174. ty1 = cy1;
  175. if (ty2 >= cy2)
  176. ty2 = cy2;
  177. if (ty1 >= ty2)
  178. return;
  179. int h = ty2 - ty1;
  180. int w = tx2 - tx1;
  181. quint32 basex;
  182. quint32 srcy;
  183. if (sx < 0) {
  184. int dstx = qFloor((tx1 + qreal(0.5) - targetRect.right()) * ix) + 1;
  185. basex = quint32(srcRect.right() * 65536) + dstx;
  186. } else {
  187. int dstx = qCeil((tx1 + qreal(0.5) - targetRect.left()) * ix) - 1;
  188. basex = quint32(srcRect.left() * 65536) + dstx;
  189. }
  190. if (sy < 0) {
  191. int dsty = qFloor((ty1 + qreal(0.5) - targetRect.bottom()) * iy) + 1;
  192. srcy = quint32(srcRect.bottom() * 65536) + dsty;
  193. } else {
  194. int dsty = qCeil((ty1 + qreal(0.5) - targetRect.top()) * iy) - 1;
  195. srcy = quint32(srcRect.top() * 65536) + dsty;
  196. }
  197. quint32 *dst = ((quint32 *) (destPixels + ty1 * dbpl)) + tx1;
  198. while (h--) {
  199. const uint *src = (const quint32 *) (srcPixels + (srcy >> 16) * sbpl);
  200. int srcx = basex;
  201. int x = 0;
  202. for (; x<w; ++x) {
  203. blender.write(&dst[x], src[srcx >> 16]);
  204. srcx += ix;
  205. }
  206. blender.flush(&dst[x]);
  207. dst = (quint32 *)(((uchar *) dst) + dbpl);
  208. srcy += iy;
  209. }
  210. }
  211. struct QTransformImageVertex
  212. {
  213. qreal x, y, u, v; // destination coordinates (x, y) and source coordinates (u, v)
  214. };
  215. template <class SrcT, class DestT, class Blender>
  216. void qt_transform_image_rasterize(DestT *destPixels, int dbpl,
  217. const SrcT *srcPixels, int sbpl,
  218. const QTransformImageVertex &topLeft, const QTransformImageVertex &bottomLeft,
  219. const QTransformImageVertex &topRight, const QTransformImageVertex &bottomRight,
  220. const QRect &sourceRect,
  221. const QRect &clip,
  222. qreal topY, qreal bottomY,
  223. int dudx, int dvdx, int dudy, int dvdy, int u0, int v0,
  224. Blender blender)
  225. {
  226. int fromY = qMax(qRound(topY), clip.top());
  227. int toY = qMin(qRound(bottomY), clip.top() + clip.height());
  228. if (fromY >= toY)
  229. return;
  230. qreal leftSlope = (bottomLeft.x - topLeft.x) / (bottomLeft.y - topLeft.y);
  231. qreal rightSlope = (bottomRight.x - topRight.x) / (bottomRight.y - topRight.y);
  232. int dx_l = int(leftSlope * 0x10000);
  233. int dx_r = int(rightSlope * 0x10000);
  234. int x_l = int((topLeft.x + (qreal(0.5) + fromY - topLeft.y) * leftSlope + qreal(0.5)) * 0x10000);
  235. int x_r = int((topRight.x + (qreal(0.5) + fromY - topRight.y) * rightSlope + qreal(0.5)) * 0x10000);
  236. int fromX, toX, x1, x2, u, v, i, ii;
  237. DestT *line;
  238. for (int y = fromY; y < toY; ++y) {
  239. line = reinterpret_cast<DestT *>(reinterpret_cast<uchar *>(destPixels) + y * dbpl);
  240. fromX = qMax(x_l >> 16, clip.left());
  241. toX = qMin(x_r >> 16, clip.left() + clip.width());
  242. if (fromX < toX) {
  243. // Because of rounding, we can get source coordinates outside the source image.
  244. // Clamp these coordinates to the source rect to avoid segmentation fault and
  245. // garbage on the screen.
  246. // Find the first pixel on the current scan line where the source coordinates are within the source rect.
  247. x1 = fromX;
  248. u = x1 * dudx + y * dudy + u0;
  249. v = x1 * dvdx + y * dvdy + v0;
  250. for (; x1 < toX; ++x1) {
  251. int uu = u >> 16;
  252. int vv = v >> 16;
  253. if (uu >= sourceRect.left() && uu < sourceRect.left() + sourceRect.width()
  254. && vv >= sourceRect.top() && vv < sourceRect.top() + sourceRect.height()) {
  255. break;
  256. }
  257. u += dudx;
  258. v += dvdx;
  259. }
  260. // Find the last pixel on the current scan line where the source coordinates are within the source rect.
  261. x2 = toX;
  262. u = (x2 - 1) * dudx + y * dudy + u0;
  263. v = (x2 - 1) * dvdx + y * dvdy + v0;
  264. for (; x2 > x1; --x2) {
  265. int uu = u >> 16;
  266. int vv = v >> 16;
  267. if (uu >= sourceRect.left() && uu < sourceRect.left() + sourceRect.width()
  268. && vv >= sourceRect.top() && vv < sourceRect.top() + sourceRect.height()) {
  269. break;
  270. }
  271. u -= dudx;
  272. v -= dvdx;
  273. }
  274. // Set up values at the beginning of the scan line.
  275. u = fromX * dudx + y * dudy + u0;
  276. v = fromX * dvdx + y * dvdy + v0;
  277. line += fromX;
  278. // Beginning of the scan line, with per-pixel checks.
  279. i = x1 - fromX;
  280. while (i) {
  281. int uu = qBound(sourceRect.left(), u >> 16, sourceRect.left() + sourceRect.width() - 1);
  282. int vv = qBound(sourceRect.top(), v >> 16, sourceRect.top() + sourceRect.height() - 1);
  283. blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + vv * sbpl)[uu]);
  284. u += dudx;
  285. v += dvdx;
  286. ++line;
  287. --i;
  288. }
  289. // Middle of the scan line, without checks.
  290. // Manual loop unrolling.
  291. i = x2 - x1;
  292. ii = i >> 3;
  293. while (ii) {
  294. blender.write(&line[0], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
  295. blender.write(&line[1], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
  296. blender.write(&line[2], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
  297. blender.write(&line[3], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
  298. blender.write(&line[4], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
  299. blender.write(&line[5], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
  300. blender.write(&line[6], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
  301. blender.write(&line[7], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
  302. line += 8;
  303. --ii;
  304. }
  305. switch (i & 7) {
  306. case 7: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
  307. case 6: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
  308. case 5: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
  309. case 4: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
  310. case 3: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
  311. case 2: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
  312. case 1: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
  313. }
  314. // End of the scan line, with per-pixel checks.
  315. i = toX - x2;
  316. while (i) {
  317. int uu = qBound(sourceRect.left(), u >> 16, sourceRect.left() + sourceRect.width() - 1);
  318. int vv = qBound(sourceRect.top(), v >> 16, sourceRect.top() + sourceRect.height() - 1);
  319. blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + vv * sbpl)[uu]);
  320. u += dudx;
  321. v += dvdx;
  322. ++line;
  323. --i;
  324. }
  325. blender.flush(line);
  326. }
  327. x_l += dx_l;
  328. x_r += dx_r;
  329. }
  330. }
  331. template <class SrcT, class DestT, class Blender>
  332. void qt_transform_image(DestT *destPixels, int dbpl,
  333. const SrcT *srcPixels, int sbpl,
  334. const QRectF &targetRect,
  335. const QRectF &sourceRect,
  336. const QRect &clip,
  337. const QTransform &targetRectTransform,
  338. Blender blender)
  339. {
  340. enum Corner
  341. {
  342. TopLeft,
  343. TopRight,
  344. BottomRight,
  345. BottomLeft
  346. };
  347. // map source rectangle to destination.
  348. QTransformImageVertex v[4];
  349. v[TopLeft].u = v[BottomLeft].u = sourceRect.left();
  350. v[TopLeft].v = v[TopRight].v = sourceRect.top();
  351. v[TopRight].u = v[BottomRight].u = sourceRect.right();
  352. v[BottomLeft].v = v[BottomRight].v = sourceRect.bottom();
  353. targetRectTransform.map(targetRect.left(), targetRect.top(), &v[TopLeft].x, &v[TopLeft].y);
  354. targetRectTransform.map(targetRect.right(), targetRect.top(), &v[TopRight].x, &v[TopRight].y);
  355. targetRectTransform.map(targetRect.left(), targetRect.bottom(), &v[BottomLeft].x, &v[BottomLeft].y);
  356. targetRectTransform.map(targetRect.right(), targetRect.bottom(), &v[BottomRight].x, &v[BottomRight].y);
  357. // find topmost vertex.
  358. int topmost = 0;
  359. for (int i = 1; i < 4; ++i) {
  360. if (v[i].y < v[topmost].y)
  361. topmost = i;
  362. }
  363. // rearrange array such that topmost vertex is at index 0.
  364. switch (topmost) {
  365. case 1:
  366. {
  367. QTransformImageVertex t = v[0];
  368. for (int i = 0; i < 3; ++i)
  369. v[i] = v[i+1];
  370. v[3] = t;
  371. }
  372. break;
  373. case 2:
  374. qSwap(v[0], v[2]);
  375. qSwap(v[1], v[3]);
  376. break;
  377. case 3:
  378. {
  379. QTransformImageVertex t = v[3];
  380. for (int i = 3; i > 0; --i)
  381. v[i] = v[i-1];
  382. v[0] = t;
  383. }
  384. break;
  385. }
  386. // if necessary, swap vertex 1 and 3 such that 1 is to the left of 3.
  387. qreal dx1 = v[1].x - v[0].x;
  388. qreal dy1 = v[1].y - v[0].y;
  389. qreal dx2 = v[3].x - v[0].x;
  390. qreal dy2 = v[3].y - v[0].y;
  391. if (dx1 * dy2 - dx2 * dy1 > 0)
  392. qSwap(v[1], v[3]);
  393. QTransformImageVertex u = {v[1].x - v[0].x, v[1].y - v[0].y, v[1].u - v[0].u, v[1].v - v[0].v};
  394. QTransformImageVertex w = {v[2].x - v[0].x, v[2].y - v[0].y, v[2].u - v[0].u, v[2].v - v[0].v};
  395. qreal det = u.x * w.y - u.y * w.x;
  396. if (det == 0)
  397. return;
  398. qreal invDet = 1.0 / det;
  399. qreal m11, m12, m21, m22, mdx, mdy;
  400. m11 = (u.u * w.y - u.y * w.u) * invDet;
  401. m12 = (u.x * w.u - u.u * w.x) * invDet;
  402. m21 = (u.v * w.y - u.y * w.v) * invDet;
  403. m22 = (u.x * w.v - u.v * w.x) * invDet;
  404. mdx = v[0].u - m11 * v[0].x - m12 * v[0].y;
  405. mdy = v[0].v - m21 * v[0].x - m22 * v[0].y;
  406. int dudx = int(m11 * 0x10000);
  407. int dvdx = int(m21 * 0x10000);
  408. int dudy = int(m12 * 0x10000);
  409. int dvdy = int(m22 * 0x10000);
  410. int u0 = qCeil((qreal(0.5) * m11 + qreal(0.5) * m12 + mdx) * 0x10000) - 1;
  411. int v0 = qCeil((qreal(0.5) * m21 + qreal(0.5) * m22 + mdy) * 0x10000) - 1;
  412. int x1 = qFloor(sourceRect.left());
  413. int y1 = qFloor(sourceRect.top());
  414. int x2 = qCeil(sourceRect.right());
  415. int y2 = qCeil(sourceRect.bottom());
  416. QRect sourceRectI(x1, y1, x2 - x1, y2 - y1);
  417. // rasterize trapezoids.
  418. if (v[1].y < v[3].y) {
  419. qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[0], v[1], v[0], v[3], sourceRectI, clip, v[0].y, v[1].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
  420. qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[1], v[2], v[0], v[3], sourceRectI, clip, v[1].y, v[3].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
  421. qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[1], v[2], v[3], v[2], sourceRectI, clip, v[3].y, v[2].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
  422. } else {
  423. qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[0], v[1], v[0], v[3], sourceRectI, clip, v[0].y, v[3].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
  424. qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[0], v[1], v[3], v[2], sourceRectI, clip, v[3].y, v[1].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
  425. qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[1], v[2], v[3], v[2], sourceRectI, clip, v[1].y, v[2].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
  426. }
  427. }
  428. QT_END_NAMESPACE
  429. #endif // QBLENDFUNCTIONS_P_H