1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQuick module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qsgopenvghelpers.h"
41 #include <cmath>
42 
43 QT_BEGIN_NAMESPACE
44 
45 namespace QSGOpenVGHelpers {
46 
qPainterPathToVGPath(const QPainterPath & path)47 VGPath qPainterPathToVGPath(const QPainterPath &path)
48 {
49     int count = path.elementCount();
50 
51     VGPath vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
52                                  VG_PATH_DATATYPE_F,
53                                  1.0f,        // scale
54                                  0.0f,        // bias
55                                  count + 1,   // segmentCapacityHint
56                                  count * 2,   // coordCapacityHint
57                                  VG_PATH_CAPABILITY_ALL);
58 
59     if (count == 0)
60         return vgpath;
61 
62     QVector<VGfloat> coords;
63     QVector<VGubyte> segments;
64 
65     int curvePos = 0;
66     QPointF temp;
67 
68     // Keep track of the start and end of each sub-path.  QPainterPath
69     // does not have an "implicit close" flag like QVectorPath does.
70     // We therefore have to detect closed paths by looking for a LineTo
71     // element that connects back to the initial MoveTo element.
72     qreal startx = 0.0;
73     qreal starty = 0.0;
74     qreal endx = 0.0;
75     qreal endy = 0.0;
76     bool haveStart = false;
77     bool haveEnd = false;
78 
79     for (int i = 0; i < count; ++i) {
80         const QPainterPath::Element element = path.elementAt(i);
81         switch (element.type) {
82 
83         case QPainterPath::MoveToElement:
84         {
85             if (haveStart && haveEnd && startx == endx && starty == endy) {
86                 // Implicitly close the previous sub-path.
87                 segments.append(VG_CLOSE_PATH);
88             }
89             temp = QPointF(element.x, element.y);
90             startx = temp.x();
91             starty = temp.y();
92             coords.append(startx);
93             coords.append(starty);
94             haveStart = true;
95             haveEnd = false;
96             segments.append(VG_MOVE_TO_ABS);
97         }
98             break;
99 
100         case QPainterPath::LineToElement:
101         {
102             temp = QPointF(element.x, element.y);
103             endx = temp.x();
104             endy = temp.y();
105             coords.append(endx);
106             coords.append(endy);
107             haveEnd = true;
108             segments.append(VG_LINE_TO_ABS);
109         }
110             break;
111 
112         case QPainterPath::CurveToElement:
113         {
114             temp = QPointF(element.x, element.y);
115             coords.append(temp.x());
116             coords.append(temp.y());
117             haveEnd = false;
118             curvePos = 2;
119         }
120             break;
121 
122         case QPainterPath::CurveToDataElement:
123         {
124             temp = QPointF(element.x, element.y);
125             coords.append(temp.x());
126             coords.append(temp.y());
127             haveEnd = false;
128             curvePos += 2;
129             if (curvePos == 6) {
130                 curvePos = 0;
131                 segments.append(VG_CUBIC_TO_ABS);
132             }
133         }
134             break;
135 
136         }
137     }
138 
139     if (haveStart && haveEnd && startx == endx && starty == endy) {
140         // Implicitly close the last sub-path.
141         segments.append(VG_CLOSE_PATH);
142     }
143 
144     vgAppendPathData(vgpath, segments.count(),
145                      segments.constData(), coords.constData());
146 
147     return vgpath;
148 }
149 
150 
qDrawTiled(VGImage image,const QSize imageSize,const QRectF & targetRect,const QPointF offset,float scaleX,float scaleY)151 void qDrawTiled(VGImage image, const QSize imageSize, const QRectF &targetRect, const QPointF offset, float scaleX, float scaleY) {
152 
153     //Check for valid image size and targetRect
154     if (imageSize.width() <= 0 || imageSize.height() <= 0)
155         return;
156     if (targetRect.width() <= 0 || targetRect.height() <= 0)
157         return;
158 
159     // This logic is mostly from the Qt Raster PaintEngine's qt_draw_tile
160     qreal drawH;
161     qreal drawW;
162     qreal xPos;
163     qreal xOff;
164     qreal yPos = targetRect.y();
165     qreal yOff;
166 
167     if (offset.y() < 0)
168         yOff = imageSize.height() - qRound(-offset.y()) % imageSize.height();
169     else
170         yOff = qRound(offset.y()) % imageSize.height();
171 
172 
173     // Save the current image transform matrix
174     vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
175     QVector<float> originalMatrix(9);
176     vgGetMatrix(originalMatrix.data());
177 
178     while (!qFuzzyCompare(yPos, targetRect.y() + targetRect.height()) &&
179            yPos < targetRect.y() + targetRect.height()) {
180         drawH = imageSize.height() - yOff; // Cropping first row
181         if (yPos + drawH * scaleY > targetRect.y() + targetRect.height()) { // Cropping last row
182             // Check that values aren't equal
183             if (!qFuzzyCompare((float)(yPos + drawH * scaleY), (float)(targetRect.y() + targetRect.height())))
184                 drawH = targetRect.y() + targetRect.height() - yPos;
185         }
186         xPos = targetRect.x();
187         if (offset.x() < 0)
188             xOff = imageSize.width() - qRound(-offset.x()) % imageSize.width();
189         else
190             xOff = qRound(offset.x()) % imageSize.width();
191 
192         while (!qFuzzyCompare(xPos, targetRect.x() + targetRect.width()) &&
193                xPos < targetRect.x() + targetRect.width()) {
194             drawW = imageSize.width() - xOff; // Cropping first column
195             if (xPos + drawW * scaleX > targetRect.x() + targetRect.width()) {
196                 // Check that values aren't equal
197                 if (!qFuzzyCompare((float)(xPos + drawW * scaleX), (float)(targetRect.x() + targetRect.width())))
198                     drawW = targetRect.x() + targetRect.width() - xPos;
199             }
200             if (round(drawW) > 0 && round(drawH) > 0) { // Can't source image less than 1 width or height
201                 //Draw here
202                 VGImage childRectImage = vgChildImage(image, xOff, yOff, round(drawW), round(drawH));
203                 vgTranslate(xPos, yPos);
204                 vgScale(scaleX, scaleY);
205                 vgDrawImage(childRectImage);
206                 vgDestroyImage(childRectImage);
207                 vgLoadMatrix(originalMatrix.constData());
208             }
209             if ( drawW > 0)
210                 xPos += drawW * scaleX;
211             xOff = 0;
212         }
213         if ( drawH > 0)
214             yPos += drawH * scaleY;
215         yOff = 0;
216 
217     }
218 }
219 
qDrawBorderImage(VGImage image,const QSizeF & textureSize,const QRectF & targetRect,const QRectF & innerTargetRect,const QRectF & subSourceRect)220 void qDrawBorderImage(VGImage image, const QSizeF &textureSize, const QRectF &targetRect, const QRectF &innerTargetRect, const QRectF &subSourceRect)
221 {
222     // Create normalized margins
223     QMarginsF margins(qMax(innerTargetRect.left() - targetRect.left(), qreal(0.0)),
224                       qMax(innerTargetRect.top() - targetRect.top(), qreal(0.0)),
225                       qMax(targetRect.right() - innerTargetRect.right(), qreal(0.0)),
226                       qMax(targetRect.bottom() - innerTargetRect.bottom(), qreal(0.0)));
227 
228     QRectF sourceRect(0, 0, textureSize.width(), textureSize.height());
229 
230     // Create all the subRects
231     QRectF topLeftSourceRect(sourceRect.topLeft(), QSizeF(margins.left(), margins.top()));
232     QRectF topRightSourceRect(sourceRect.width() - margins.right(), sourceRect.top(), margins.right(), margins.top());
233     QRectF bottomLeftSourceRect(sourceRect.left(), sourceRect.height() - margins.bottom(), margins.left(), margins.bottom());
234     QRectF bottomRightSourceRect(sourceRect.width() - margins.right(), sourceRect.height() - margins.bottom(), margins.right(), margins.bottom());
235 
236     QRectF topSourceRect(margins.left(), 0.0, sourceRect.width() - (margins.right() + margins.left()), margins.top());
237     QRectF topTargetRect(margins.left(), 0.0, innerTargetRect.width(), margins.top());
238     QRectF bottomSourceRect(margins.left(), sourceRect.height() - margins.bottom(), sourceRect.width() - (margins.right() + margins.left()), margins.bottom());
239     QRectF bottomTargetRect(margins.left(), targetRect.height() - margins.bottom(), innerTargetRect.width(), margins.bottom());
240     QRectF leftSourceRect(0.0, margins.top(), margins.left(), sourceRect.height() - (margins.bottom() + margins.top()));
241     QRectF leftTargetRect(0.0, margins.top(), margins.left(), innerTargetRect.height());
242     QRectF rightSourceRect(sourceRect.width() - margins.right(), margins.top(), margins.right(), sourceRect.height() - (margins.bottom() + margins.top()));
243     QRectF rightTargetRect(targetRect.width() - margins.right(), margins.top(), margins.right(), innerTargetRect.height());
244 
245     QRectF centerSourceRect(margins.left(), margins.top(), sourceRect.width() - (margins.right() + margins.left()), sourceRect.height() - (margins.top() + margins.bottom()));
246 
247     // Draw the 9 different sections
248     // (1) Top Left (unscaled)
249     qDrawSubImage(image,
250                  topLeftSourceRect,
251                  targetRect.topLeft());
252 
253     // (3) Top Right (unscaled)
254     qDrawSubImage(image,
255                  topRightSourceRect,
256                  QPointF(targetRect.width() - margins.right(), 0.0));
257 
258     // (7) Bottom Left (unscaled)
259     qDrawSubImage(image,
260                  bottomLeftSourceRect,
261                  QPointF(targetRect.left(), targetRect.height() - margins.bottom()));
262 
263     // (9) Bottom Right (unscaled)
264     qDrawSubImage(image,
265                  bottomRightSourceRect,
266                  QPointF(targetRect.width() - margins.right(), targetRect.height() - margins.bottom()));
267 
268     double scaledWidth = 1.0;
269     double scaledHeight = 1.0;
270 
271     // (2) Top (scaled via horizontalTileRule)
272     VGImage topImage = vgChildImage(image, topSourceRect.x(), topSourceRect.y(), topSourceRect.width(), topSourceRect.height());
273     scaledWidth = (topTargetRect.width() / subSourceRect.width()) / topSourceRect.width();
274 
275     QSGOpenVGHelpers::qDrawTiled(topImage, topSourceRect.size().toSize(), topTargetRect, QPoint(0.0, 0.0), scaledWidth, 1);
276 
277     vgDestroyImage(topImage);
278 
279     // (8) Bottom (scaled via horizontalTileRule)
280     VGImage bottomImage = vgChildImage(image, bottomSourceRect.x(), bottomSourceRect.y(), bottomSourceRect.width(), bottomSourceRect.height());
281     scaledWidth = (bottomTargetRect.width() / subSourceRect.width()) / bottomSourceRect.width();
282 
283     QSGOpenVGHelpers::qDrawTiled(bottomImage, bottomSourceRect.size().toSize(), bottomTargetRect, QPoint(0.0, 0.0), scaledWidth, 1);
284 
285     vgDestroyImage(bottomImage);
286 
287     // (4) Left (scaled via verticalTileRule)
288     VGImage leftImage = vgChildImage(image, leftSourceRect.x(), leftSourceRect.y(), leftSourceRect.width(), leftSourceRect.height());
289     scaledHeight = (leftTargetRect.height() / subSourceRect.height()) / leftSourceRect.height();
290     QSGOpenVGHelpers::qDrawTiled(leftImage, leftSourceRect.size().toSize(), leftTargetRect, QPointF(0.0, 0.0), 1, scaledHeight);
291 
292     vgDestroyImage(leftImage);
293 
294     // (6) Right (scaled via verticalTileRule)
295     VGImage rightImage = vgChildImage(image, rightSourceRect.x(), rightSourceRect.y(), rightSourceRect.width(), rightSourceRect.height());
296     scaledHeight = (rightTargetRect.height() / subSourceRect.height()) / rightSourceRect.height();
297 
298     QSGOpenVGHelpers::qDrawTiled(rightImage, rightSourceRect.size().toSize(), rightTargetRect, QPointF(0, 0), 1, scaledHeight);
299 
300     vgDestroyImage(rightImage);
301 
302     // (5) Center (saled via verticalTileRule and horizontalTileRule)
303     VGImage centerImage = vgChildImage(image, centerSourceRect.x(), centerSourceRect.y(), centerSourceRect.width(), centerSourceRect.height());
304 
305     scaledWidth = (innerTargetRect.width() / subSourceRect.width()) / centerSourceRect.width();
306     scaledHeight = (innerTargetRect.height() / subSourceRect.height()) / centerSourceRect.height();
307 
308     QSGOpenVGHelpers::qDrawTiled(centerImage, centerSourceRect.size().toSize(), innerTargetRect, QPointF(0, 0), scaledWidth, scaledHeight);
309 
310     vgDestroyImage(centerImage);
311 }
312 
qDrawSubImage(VGImage image,const QRectF & sourceRect,const QPointF & destOffset)313 void qDrawSubImage(VGImage image, const QRectF &sourceRect, const QPointF &destOffset)
314 {
315     // Check for valid source size
316     if (sourceRect.width() <= 0 || sourceRect.height() <= 0)
317         return;
318 
319     // Save the current image transform matrix
320     vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
321     QVector<float> originalMatrix(9);
322     vgGetMatrix(originalMatrix.data());
323 
324     // Get the child Image
325     VGImage childRectImage = vgChildImage(image, sourceRect.x(), sourceRect.y(), sourceRect.width(), sourceRect.height());
326     vgTranslate(destOffset.x(), destOffset.y());
327     vgDrawImage(childRectImage);
328     vgDestroyImage(childRectImage);
329 
330     // Pop Matrix
331     vgLoadMatrix(originalMatrix.constData());
332 }
333 
qColorToVGColor(const QColor & color,float opacity)334 const QVector<VGfloat> qColorToVGColor(const QColor &color, float opacity)
335 {
336     QVector<VGfloat> vgColor(4);
337     vgColor[0] = color.redF();
338     vgColor[1] = color.greenF();
339     vgColor[2] = color.blueF();
340     vgColor[3] = color.alphaF() * opacity;
341     return vgColor;
342 }
343 
qImageFormatToVGImageFormat(QImage::Format format)344 VGImageFormat qImageFormatToVGImageFormat(QImage::Format format)
345 {
346     VGImageFormat vgFormat;
347 
348     switch (format) {
349     case QImage::Format_Mono:
350     case QImage::Format_MonoLSB:
351         vgFormat = VG_BW_1;
352         break;
353     case QImage::Format_RGB32:
354         vgFormat = VG_sXRGB_8888;
355         break;
356     case QImage::Format_ARGB32:
357         vgFormat = VG_sARGB_8888;
358         break;
359     case QImage::Format_ARGB32_Premultiplied:
360         vgFormat = VG_sARGB_8888_PRE;
361         break;
362     case QImage::Format_RGB16:
363         vgFormat = VG_sRGB_565;
364         break;
365     case QImage::Format_RGBX8888:
366         vgFormat = VG_sRGBX_8888;
367         break;
368     case QImage::Format_RGBA8888:
369         vgFormat = VG_sRGBA_8888;
370         break;
371     case QImage::Format_RGBA8888_Premultiplied:
372         vgFormat = VG_sRGBA_8888_PRE;
373         break;
374     case QImage::Format_Alpha8:
375         vgFormat = VG_A_8;
376         break;
377     case QImage::Format_Grayscale8:
378         vgFormat = VG_sL_8;
379         break;
380     default:
381         //Invalid
382         vgFormat = (VGImageFormat)-1;
383         break;
384     }
385 
386     return vgFormat;
387 }
388 
qVGImageFormatToQImageFormat(VGImageFormat format)389 QImage::Format qVGImageFormatToQImageFormat(VGImageFormat format)
390 {
391     QImage::Format qImageFormat;
392 
393     switch (format) {
394     case VG_BW_1:
395         qImageFormat = QImage::Format_Mono;
396         break;
397     case VG_sXRGB_8888:
398         qImageFormat = QImage::Format_RGB32;
399         break;
400     case VG_sARGB_8888:
401         qImageFormat = QImage::Format_ARGB32;
402         break;
403     case VG_sARGB_8888_PRE:
404         qImageFormat = QImage::Format_ARGB32_Premultiplied;
405         break;
406     case VG_sRGB_565:
407         qImageFormat = QImage::Format_RGB16;
408         break;
409     case VG_sRGBX_8888:
410         qImageFormat = QImage::Format_RGBX8888;
411         break;
412     case VG_sRGBA_8888:
413         qImageFormat = QImage::Format_RGBA8888;
414         break;
415     case VG_sRGBA_8888_PRE:
416         qImageFormat = QImage::Format_RGBA8888_Premultiplied;
417         break;
418     case VG_A_8:
419         qImageFormat = QImage::Format_Alpha8;
420         break;
421     case VG_sL_8:
422         qImageFormat = QImage::Format_Grayscale8;
423     default:
424         qImageFormat = QImage::Format_ARGB32;
425         break;
426     }
427 
428     return qImageFormat;
429 }
430 
431 } // end namespace QSGOpenVGHelpers
432 
433 QT_END_NAMESPACE
434